Locking with redis

We had been looking at using zookeeper (or consul) for locking, rather than postgres rowlocks; but once we realised we didn’t really fancy running a quorum, it seemed just as simple to use redis (which we already had as a session store), instead of a single node of either.

While there is a full-blown lock protocol, all you really need (for our use case) is a key, with a ttl. And some sort of CAS operation.

If you are using the latest redis version (i.e. 6, or 7), then the SET command has some extra options to make this simple:

    async function withLock(id, cb) {
        const key = `/lock/${id}`;
        const val = await redis.set(key, "true", {
            EX: 60,
            KEEPTTL: true,
            GET: true,
        });
        if (val !== null) {
            throw new Error("already locked");
        }
        try {
            const res = await cb();
            return res;
        } finally {
            await redis.del(key);
        }
    };

First, you attempt to acquire the lock (i.e. set some value for a specific key). If the key already exists, you bail; otherwise, you do your business and then free the lock. If the process dies, the lock will be released, when the ttl expires.

If you are using an older redis version (e.g. 4), and don’t fancy upgrading; it is still possible, you just need to explicitly set the TTL (after acquiring the lock):

async function withLock(id, cb) {
        const key = `/lock/${id}`;
        const val = await redis.getset(key, "true");
        if (val !== null) {
            throw new Error("already locked");
        }
        await redis.expire(key, 5 * 60);
        try {
        ...
    };

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s