Powers to provide synchronization primitives for Andi skills across concurrent async processes, replicas, and beyond. These primitives are distributed and can be shared across skill versions or across all skills in an organization.

Mutexes help exclusive access to a shared resource.

Semaphores help with allowing shared access to a shared resource, up to a defined limit.

Hierarchy

  • LockPowers

Index

Methods

Static createMutex

  • throws

    {TypeError} When key is nil

    throws

    {RangeError} When key is empty or longer than 256 characters

    example

    Safely using a mutex by always releasing

    // Ensure you import LockPowers
    import { LockPowers } from "@andi/powers";
    
    const mutex = await LockPowers.createMutex("my-lock");
    try {
        // may throw `LockAcquireTimeoutError`. To avoid errors, can also use `.tryAcquire()`
        await mutex.acquire();
        // critical code
    } finally {
        await mutex.release();
    }

    Parameters

    • key: string

      Unique key for lock shared across options.scope

    • Optional options: LockOptions

    Returns Promise<DistributedMutex>

Static createSemaphore

  • No guaranteed fairness, but measures to minimize fairness issues in place.

    throws

    {TypeError} When key is nil

    throws

    {RangeError} When key is empty or longer than 256 characters

    throws

    {RangeError} When maxCount is not in range [1, 1024]

    throws

    {Error} Various errors when options are invalid. See LockOptions for more information

    example

    Safely using a semaphore by always releasing

    // Ensure you import LockPowers
    import { LockPowers } from "@andi/powers";
    
    // acquire one of the 5 leases to my-shared-lock
    const semaphore = await LockPowers.createSemaphore("my-shared-lock", 5);
    try {
        // may throw `LockAcquireTimeoutError`. To avoid errors, can also use `.tryAcquire()`
        await semaphore.acquire();
        // critical code with at most 5 concurrent processes
    } finally {
        await semaphore.release();
    }

    Parameters

    • key: string

      Unique key for lock shared across options.scope.

    • maxCount: number

      Number of concurrent access

    • Optional options: LockOptions

    Returns Promise<DistributedSemaphore>

Static runExclusive

  • runExclusive<T>(key: string, callback: () => T | Promise<T>, options?: LockOptions): Promise<T>
  • Fits most use cases. Acquires the lock, runs the provided callback, and then releases the lock.

    For workflows that span multiple skills, be sure to pass LockScope.Organization as the scope argument for LockOptions.

    example

    In this example, the skill audits a business workflow managed by the skill. The workflow has been crafted where all updates and deletions to audit data are done through the "audit-update" lock.

    Reads of audit data do not require a lock.

    Additions of new audit do not require a lock if they are keyed uniquely with PowerHelpers.uuid() or another unique identifier.

    In failure scenarios, the "audit-update" lock is naturally released after the expiration of the lockTimeout. Advanced handling of errors and results can help further refine a critical business workflow.

    // Ensure you import LockPowers
    import { LockPowers, DataPowers } from "@andi/powers";
    
    const exclusiveResult = await LockPowers.runExclusive("audit-update", async () => {
        try {
            const audits = await DataPowers.getOrCreateCollection<SkillAudit>(CollectionType.Dictionary, "skill-audits", { expiry: { expireMode: CollectionExpirationMode.Never } });
            const auditToUpdate = await audits.get(auditId);
            if (!auditToUpdate) return false;
            auditToUpdate.status = false;
            return true;
        }
        catch (err) {
            return false;
        }
    });

    Type parameters

    • T = unknown

    Parameters

    • key: string

      Unique key for lock shared across options.scope

    • callback: () => T | Promise<T>

      A function containing the callback to run exclusively

        • (): T | Promise<T>
        • Returns T | Promise<T>

    • Optional options: LockOptions

    Returns Promise<T>

    A promise that resolves with the result of the callback, or rejects if an error occurs

Generated using TypeDoc