From 08c68fc5cd5900045e34cc1f4d592e24784e49ea Mon Sep 17 00:00:00 2001 From: Ryan Roberts Date: Sun, 23 Jul 2023 10:21:01 -0700 Subject: [PATCH] Fix: Redis race conditions with .set, .delete. and .clear when useRedisSets=true --- packages/redis/src/index.ts | 38 ++++++++++++++++++++++++++++--------- 1 file changed, 29 insertions(+), 9 deletions(-) diff --git a/packages/redis/src/index.ts b/packages/redis/src/index.ts index ad3062d4a..634dc0b72 100644 --- a/packages/redis/src/index.ts +++ b/packages/redis/src/index.ts @@ -73,22 +73,37 @@ class KeyvRedis extends EventEmitter { key = this._getKeyName(key); - if (typeof ttl === 'number') { - await this.redis.set(key, value, 'PX', ttl); - } else { - await this.redis.set(key, value); - } + const set = async (redis: any) => { + if (typeof ttl === 'number') { + await redis.set(key, value, 'PX', ttl); + } else { + await redis.set(key, value); + } + }; if (this.opts.useRedisSets) { - await this.redis.sadd(this._getNamespace(), key); + const trx = await this.redis.multi(); + await set(trx); + await trx.sadd(this._getNamespace(), key); + await trx.exec(); + } else { + await set(this.redis); } } async delete(key: string): DeleteOutput { key = this._getKeyName(key); - const items: number = await this.redis.del(key); + let items = 0; + const del = async (redis: any) => redis.del(key); + if (this.opts.useRedisSets) { - await this.redis.srem(this._getNamespace(), key); + const trx = this.redis.multi(); + await del(trx); + await trx.srem(this._getNamespace(), key); + const r = await trx.exec(); + items = r[0][1]; + } else { + items = await del(this.redis); } return items > 0; @@ -104,7 +119,12 @@ class KeyvRedis extends EventEmitter { async clear(): ClearOutput { if (this.opts.useRedisSets) { const keys: string[] = await this.redis.smembers(this._getNamespace()); - await this.redis.del([...keys, this._getNamespace()]); + if (keys.length > 0) { + await Promise.all([ + this.redis.del([...keys]), + this.redis.srem(this._getNamespace(), [...keys]), + ]); + } } else { const pattern = 'sets:*'; const keys: string[] = await this.redis.keys(pattern);