Skip to content

Commit

Permalink
Merge pull request #8 from coligo-tech/dev
Browse files Browse the repository at this point in the history
Add types
  • Loading branch information
AmrSaber committed Jun 10, 2021
2 parents c28ceb5 + 4dcdc3c commit bdd8eb9
Show file tree
Hide file tree
Showing 5 changed files with 57 additions and 25 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
name: Release

on:
push:
branches:
Expand Down
42 changes: 42 additions & 0 deletions index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { Redis } from 'ioredis';

/**
* Release the lock only if it has the same lockValue as acquireLock sets it.
* This will not release an already released token.
*/
type ReleaseFunction = () => Promise<void>;

interface acquireOptions {
/**
* Time interval at which attempt to acquire the lock.
*
* @default 100
*/
retryTimeMillis?: number;

/**
* Time span after which the acquired lock times out and is released.
*/
timeoutMillis?: number;

/**
* Time span after which will not attempt to acquire the lock, and the `lock` function will fail.
*/
failAfterMillis?: number;
}

/**
* Acquire mutex lock on the given resource name.
* If the lock is already acquired, wait until it's free and acquire it.
*
* @param client ioredis instance.
* @param lockName the name of the lock to be acquired.
* @param options lock acquire options.
*
* @returns a promise that resolves with release function.
*/
export function lock(
client: Redis,
lockName: string,
options: acquireOptions
): Promise<ReleaseFunction>;
28 changes: 8 additions & 20 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,5 @@
const crypto = require('crypto');

/**
* Acquire mutex lock on the given resource name. If the lock is already acquired, wait until it's free and acquire it.
*
* @param {import('ioredis').Redis} client
* @param {String} lockName
* @param {Object} [options]
* @param {Number} [options.retryTimeMillis=100]
* @param {Number} [options.timeoutMillis]
* @param {Number} [options.failAfterMillis]
*
* @returns {Promise<Function>} release function
*/
async function lock(client, lockName, { retryTimeMillis = 100, timeoutMillis, failAfterMillis } = {}) {
const lockValue = crypto.randomBytes(50).toString('hex');
const lockKey = `@simple-redis-mutex:lock-${lockName}`;
Expand Down Expand Up @@ -56,14 +44,13 @@ async function lock(client, lockName, { retryTimeMillis = 100, timeoutMillis, fa
attempt();
});

/**
* Release the lock only if it has the same lockValue as acquireLock sets it.
* This will prevent the release of an already released token.
*
* @returns {Promise}
*/
function releaseLock() {
// Script source: https://redis.io/commands/set#patterns - Redis official docs
/*
* Release the lock only if it has the same lockValue as acquireLock sets it.
* This will prevent the release of an already released lock.
*
* Script source: https://redis.io/commands/set#patterns - Redis official docs
*/
const luaReleaseScript = `
if redis.call("get", KEYS[1]) == ARGV[1]
then
Expand All @@ -73,7 +60,8 @@ async function lock(client, lockName, { retryTimeMillis = 100, timeoutMillis, fa
end
`;

return client.eval(luaReleaseScript, 1, lockKey, lockValue);
// After calling the script, make sure to return void promise.
return client.eval(luaReleaseScript, 1, lockKey, lockValue).then(() => {});
}

await acquireLock;
Expand Down
8 changes: 4 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "simple-redis-mutex",
"version": "1.0.3",
"version": "1.1.0",
"description": "Mutex lock implemented using redis",
"main": "index.js",
"scripts": {
Expand Down

0 comments on commit bdd8eb9

Please sign in to comment.