52 lines
1.2 KiB
TypeScript
52 lines
1.2 KiB
TypeScript
import type { MutexOptions } from "./types";
|
|
import redis from "redis";
|
|
|
|
type RedisClient = redis.RedisClientType<
|
|
redis.RedisDefaultModules & redis.RedisModules,
|
|
redis.RedisFunctions,
|
|
redis.RedisScripts
|
|
>;
|
|
|
|
export class MutexLock {
|
|
redisClient: RedisClient;
|
|
mutexOptions: MutexOptions;
|
|
|
|
constructor(redisClient: RedisClient, options: MutexOptions) {
|
|
this.mutexOptions = options;
|
|
this.redisClient = redisClient;
|
|
}
|
|
|
|
static async create(options: MutexOptions) {
|
|
const redisClient = await redis
|
|
.createClient({
|
|
url: `redis://${options.redis.host}:${options.redis.port}`,
|
|
})
|
|
.connect();
|
|
|
|
return new MutexLock(redisClient, options);
|
|
}
|
|
|
|
async obtainLock(lockName: string) {
|
|
const lockIdentifier = `mutexlock:${lockName}`;
|
|
const releaseFunc = async () => {
|
|
await this.redisClient.del(lockIdentifier);
|
|
};
|
|
|
|
while (true) {
|
|
const acquired = await this.redisClient.set(lockIdentifier, "1", {
|
|
NX: true
|
|
});
|
|
|
|
if (acquired) {
|
|
await this.redisClient.expire(
|
|
lockIdentifier,
|
|
this.mutexOptions.mutex?.ttl || 60
|
|
);
|
|
return releaseFunc;
|
|
}
|
|
await new Promise(resolve =>
|
|
setTimeout(resolve, this.mutexOptions.mutex?.checkInterval || 100)
|
|
);
|
|
}
|
|
}}
|