Skip to content

Instantly share code, notes, and snippets.

@mattfysh
Created October 25, 2021 05:12
Show Gist options
  • Save mattfysh/2fd13d7468bdd8f64173561792453019 to your computer and use it in GitHub Desktop.
Save mattfysh/2fd13d7468bdd8f64173561792453019 to your computer and use it in GitHub Desktop.
Memolock JS
import Redis from 'ioredis'
const {
HOST: host,
PORT: port,
} = process.env
const redis = new Redis({ host, port })
const subscribe = async (key, notifKey) => {
const subclient = new Redis({ host, port })
await subclient.subscribe(notifKey)
// re-get in case we missed notifKey by a hair after lock attempt
let value = await redis.get(key)
if (!value) {
value = await new Promise(resolve => {
subclient.on('message', (channel, message) => {
if (channel === notifKey) {
resolve(message)
}
})
})
}
await subclient.unsubscribe(notifKey)
await subclient.disconnect()
return value
}
export const memolock = async (key, ttl, generateValue) => {
// FIXME: the value might be there, but considered stale because missing alive:key
let value = await redis.get(key)
if (!value) {
const lockKey = `lock:${key}`
const notifKey = `notif:${key}`
const lock = await redis.set(lockKey, true, 'EX', ttl, 'NX')
if (lock) {
value = await generateValue()
await redis
.pipeline()
.set(key, value, 'EX', ttl)
.publish(notifKey, value)
.exec()
} else {
value = await subscribe(key, notifKey)
}
}
return value
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment