Library / SDK
go-redsync/redsync avatar
go-redsync/redsync

Redsync: a Redis distributed mutex for Go, and the cases where it is the wrong tool

Distributed mutual exclusion lock using Redis for Go

4,048 stars350 forksGoBSD-3-Clause

At a glance

What is it?
Redsync implements the Redlock proposal as a Go library with pluggable Redis drivers. It is small, BSD-3-Clause, and honest about the fact that the algorithm has never been formally analyzed.
Who is it for?
Adopt Redsync when you need a short-lived mutual exclusion lock across Go processes and you accept the Redlock caveats the README states outright. Do not adopt it as a correctness guarantee for financial or inventory writes, and do not use it where a single Redis instance is the only failure domain you can tolerate.
Can I use it commercially?
Yes. BSD-3-Clause is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 4 days ago.
What is it written in?
Mainly Go, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 29, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The problem Redsync solves, and who actually needs it

Multiple Go processes often need to run the same piece of work exactly once at a time: a cron job that must not overlap with its previous run, a cache rebuild, a migration step, a leader election among replicas. In-process sync.Mutex does nothing across processes, and a database row lock ties you to that database. Redsync puts the mutual exclusion in Redis, which most Go services already run, and exposes it as a mutex you lock and unlock by name.

The intended audience is Go developers who already have Redis in their stack and need coarse-grained coordination, not a general-purpose distributed lock service. The README lists three real users: Sourcegraph uses it in an internal cache, Open Match uses it with its state store, and Gocron uses it in its distributed job scheduler. Those are all cases where the lock protects a scheduling decision rather than a data invariant, which matches the algorithm's strength.

How the lock works: a pool, a mutex name, and a Redis-backed key

The architecture is deliberately thin. You build a Redis pool, wrap it in a redsync instance, and ask that instance for a mutex by name. The name is the lock identity: every process that passes the same string contends for the same lock. Internally the library keeps a redis.Pool interface, so the driver choice is a wrapper rather than a fork of the algorithm. The repository ships drivers for redigo, go-redis (v6 through v9) and valkey-go, which is visible in go.mod and in the examples/goredis, examples/redigo and examples/valkego directories.

The locking semantics follow the Redlock proposal that the README links to. A lock attempt sets a key with a TTL and an owner value; Unlock returns a boolean and an error, and the example treats a false boolean or a non-nil error as a failure. That boolean is the part people misread: it is not a network status, it is whether the release was accepted, so a false value means you may no longer own the lock you thought you held. The library does not make your critical section safe by itself; it only tells you who holds the key.

Installing Redsync and taking a first lock

The README gives one install command. It pulls the module and the driver implementations; only the driver you import ends up in your binary.

bash
go get github.com/go-redsync/redsync/v4

The README's usage example wires go-redis v9 to Redsync, creates a mutex by name, locks it, and unlocks it. Note the import paths: the driver lives under the redis/goredis/v9 subpackage, not the root module.

go
client := goredislib.NewClient(&goredislib.Options{
	Addr: "localhost:6379",
})
pool := goredis.NewPool(client)
rs := redsync.New(pool)
mutex := rs.NewMutex("my-global-mutex")
if err := mutex.Lock(); err != nil {
	panic(err)
}
if ok, err := mutex.Unlock(); !ok || err != nil {
	panic("unlock failed")
}

What you should see when this runs against a reachable Redis at localhost:6379 is a successful Lock, then an Unlock that returns true and a nil error. If Redis is unreachable, Lock returns a non-nil error and the README's example panics. The README does not document lock retry counts, expiry tuning or context cancellation in the usage section; for those you have to read the reference documentation or mutex.go in the repository.

The limitation the project states itself

The disclaimer in the README is unusually direct for a locking library: the code implements an algorithm that is currently a proposal, it was not formally analyzed, and you should understand how it works before using it in production. That is not boilerplate. It means the correctness argument for Redsync rests on the Redlock paper's assumptions, and the maintainers decline to strengthen the claim.

The practical failure mode is the one that follows from any TTL-based lock: if your critical section runs longer than the lock's expiry, the key disappears while you are still working, another process acquires the same name, and both of you proceed. Redsync cannot detect this for you. A paused goroutine, a garbage collection stop, a slow downstream call, or a clock adjustment on the Redis host all push you toward that window. There is also the single-point-of-failure shape: with one Redis instance, a failover can lose the lock key entirely, and the README does not document a fencing-token mechanism that would let a downstream resource reject a stale holder. If your work must be exactly-once against a database, a unique constraint or a transactional check belongs in that database, not in a Redis key.

Redsync against a plain SET NX EX, and against heavier lock services

The obvious alternative is not another library; it is doing it yourself with SET key value NX EX seconds plus a Lua compare-and-delete on release. That is roughly what Redsync does under the hood, and it is a legitimate choice for a single Redis instance. The difference is that Redsync packages the release script, the pool abstraction, the mutex-name API and the driver compatibility matrix, so you do not reimplement the compare-and-delete step incorrectly. If you only ever talk to one Redis and you have already written that Lua script, Redsync adds a dependency for convenience rather than capability.

A different class of alternative is a coordination service such as etcd or ZooKeeper, where the lock is backed by a consensus protocol rather than a single Redis key. The trade-off is operational: you add a second stateful system to run and monitor. Redsync's advantage is that it rides on infrastructure you already have. Its disadvantage is that it inherits Redis's failure semantics instead of replacing them. Choosing between them is really a question of whether your lock protects a scheduling decision (Redis is fine) or a data invariant (consensus, or a database-level guard, is the safer place).

Maintenance, module requirements and licence

The repository is not archived, and the last push was on 2026-09-21, which is two days before this article. The module declares go 1.26.0 in go.mod, so a project pinned to an older Go toolchain will need to move before it can depend on Redsync v4. The dependency list is broad by design: it carries redigo, go-redis v6, v7, v8 and v9, rueidis, and valkey-go, plus golang.org/x/sync. That breadth is what makes the driver choice free at build time, but it also means the module graph carries several Redis clients you will not compile.

One detail worth noticing in go.mod is the retraction of v4.14.0. If you are upgrading from an older release and your tooling resolves to v4.14.0, that version is retracted by the maintainers. The Makefile shows the project's own quality gate: go test -race ./... for tests, and staticcheck for linting. There are no release notes in the repository, so upgrade cost between minor versions cannot be assessed from what is published here.

The licence is BSD-3-Clause, a permissive licence that permits use in closed-source products provided the copyright notice and disclaimer are retained. That is a statement about the licence text, not legal advice; if you redistribute Redsync inside a product, have your own counsel read the LICENSE file.

Editorial conclusion

Adopt Redsync when you need a short-lived mutual exclusion lock across Go processes and you accept the Redlock caveats the README states outright. Do not adopt it as a correctness guarantee for financial or inventory writes, and do not use it where a single Redis instance is the only failure domain you can tolerate. Before writing code, verify two things in the repository: which driver package matches your Redis client, and whether your go.mod can move to the go directive in go.mod (go 1.26.0), since the module requires it. Then read mutex.go to see how the lock's expiry and retry behaviour are configured, because that is where your failure mode lives.

Frequently asked questions

What is a Redsync lock and how is it used in Go?

Redsync provides a Redis-based distributed mutual exclusion lock for Go, following the Redlock proposal. You create a pool for your Redis client, pass it to redsync.New, call rs.NewMutex with a name, and then Lock and Unlock that mutex; every process using the same name contends for the same lock.

What does the Redis connection look like in the Redsync example?

The README example creates a go-redis client with Addr set to localhost:6379, wraps it with goredis.NewPool, and passes that pool to redsync.New. The library also accepts a redigo pool or any pool implementing the redis.Pool interface.

Which Redis drivers does Redsync support?

go.mod lists redigo, go-redis v6 through v9, rueidis, and valkey-go, and the repository has examples/goredis, examples/redigo and examples/valkego directories. The README notes that both driver implementations are installed but only the one you use is included in your project.

Is Redsync safe to use in production?

The README's own disclaimer states that it implements an algorithm which is currently a proposal, that it was not formally analyzed, and that you should understand how it works before using it in production. The project does not claim a stronger guarantee than that.

What happens if Redsync fails to acquire the lock?

In the README example, mutex.Lock returns an error and the example panics on it, and mutex.Unlock returns a boolean plus an error where a false boolean or non-nil error is treated as a failed release. The README does not document a retry or backoff configuration in its usage section.

Official sources

  1. go-redsync/redsync on GitHub
  2. Issues
  3. License: BSD-3-Clause
  4. Project website
  5. README
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/go-redsync-redsync.svg)](https://hysenlabs.com/projects/go-redsync-redsync)