diff --git a/deps.ts b/deps.ts index b4f0029..b2c6fb6 100644 --- a/deps.ts +++ b/deps.ts @@ -2,4 +2,5 @@ export * as http from "https://deno.land/std@0.154.0/http/mod.ts"; export * as log from "https://deno.land/std@0.154.0/log/mod.ts"; export * as hex from "https://deno.land/std@0.154.0/encoding/hex.ts"; export * as redis from "https://deno.land/x/redis@v0.27.0/mod.ts"; +export { Lock } from "https://deno.land/x/async@v1.1.5/mod.ts"; export { default as TTLCache } from "https://deno.land/x/ttl@1.0.1/mod.ts"; diff --git a/lib/manager.ts b/lib/manager.ts index 63148d1..c3c5f86 100644 --- a/lib/manager.ts +++ b/lib/manager.ts @@ -1,4 +1,4 @@ -import { log, redis, TTLCache } from "../deps.ts"; +import { Lock, log, redis, TTLCache } from "../deps.ts"; import config from "./config.ts"; const KEY_EXPIRY = 3; // seconds @@ -22,10 +22,12 @@ class LocalCommentManager implements CommentManager { class RedisCommentManager implements CommentManager { private connectOptions: redis.RedisConnectOptions; + private lock: Lock; private _redis: Promise | undefined; constructor(options: redis.RedisConnectOptions) { this.connectOptions = options; + this.lock = new Lock(); } // manual lazy init, redis.createLazyClient currently doesn't support pipelines :/ @@ -40,16 +42,21 @@ class RedisCommentManager implements CommentManager { } async getAndIncrement(key: string): Promise { - const redis = await this.redis(); - key = `reviewcomment:${key}`; + await this.lock.acquire(); + try { + const redis = await this.redis(); + key = `reviewcomment:${key}`; - const pl = redis.pipeline(); - pl.incr(key); - pl.expire(key, KEY_EXPIRY); - const results = await pl.flush(); + const pl = redis.pipeline(); + pl.incr(key); + pl.expire(key, KEY_EXPIRY); + const results = await pl.flush(); - const newValue = results[0] as number; - return newValue - 1; // return old value + const newValue = results[0] as number; + return newValue - 1; // return old value + } finally { + this.lock.release(); + } } }