Skip to main content

Distributed lock management

Manage access to your shared resources in real-time to transact data in the desired order

On some occasions, there are resources shared between application instances that need to take turns accessing resources. For example, when incrementing a value, if two clients read the value at nearly the same time and both read it as 1, then each will write the value back as 2 when in reality you need the first read to complete its write before the next client reads, leading to an incremented value of 3. This scenario is an example of a race condition, which is undesirable situation that occurs when a system attempts to perform two or more operations at the same time, but because of the nature of the system, the operations must be done in the proper sequence to be done correctly. Squid provides a distributed lock for developers to use to properly synchronize shared data and resolve race conditions.

Creating a distributed lock

To synchronize access to a shared resource, you can use the acquireLock method, passing a string value for the parameter mutex that uniquely identifies this lock and an optional timeout. If no timeout is provided, the default value is 1000ms.

Client code
const distLock = await squid.acquireLock('YOUR_MUTEX_STRING', 5000); // Setting the timeout to 5000ms

This method returns a promise that resolves distributed lock for the given mutex. If the lock is not available because another client has secured it, then the promise waits to resolve until the lock is released or until the given timeout is reached.

Releasing the lock

The lock is released when the release() method is called or when the connection to the server is lost. If the client disconnects, the lock is released automatically.

Client code
// Release the lock when the work is completed
distLock.release();

Putting these methods together, your workflow could look like the following:

Client code
const distLock = await squid.acquireLock('YOUR_MUTEX_STRING', 5000);

try {
// Take action on a shared resource
} catch (e) {
// Catch errors like timeout
} finally {
distLock.release(); // Release the lock when no longer needed
}

To check if a lock has been released, use the isReleased() method. This method returns a boolean that is true if the lock has been released.

Client code
console.log(distLock.isReleased()); // true or false

You can take actions upon lock release using the observeRelease() method. This returns an observable that emits when the lock is released.

Client code
distLock.observeRelease().subscribe(() => {
// Do something upon releasing the lock
});

Managing a distributed lock with a callback

You can also use the withLock() method to manage a distributed lock. This method executes a given callback while holding a lock for the given mutex. The lock is released when the callback finishes, so the release() method is not required when using `withLock().

Client code
squid.withLock('YOUR_MUTEX_STRING', 5000, async () => {
// Complete tasks like reading and/or updating data
return; // Can also return a function
});

Securing distributed locks

By default, distributed locks are fully secured and can only be invoked if a Squid backend security function allows it. To learn more, view the backend documentation on securing distributed locks.