Library / SDK
failsafe-go/failsafe-go avatar
failsafe-go/failsafe-go

failsafe-go: resilience policies you compose rather than nest

Fault tolerance and resilience patterns for Go

2,253 stars49 forksGoMIT

At a glance

What is it?
A Go library built around one idea, wrapping a call with policies that combine into retry, circuit breaker, bulkhead, rate limiter, cache, timeout and hedge.
Who is it for?
failsafe-go earns its place when a service makes calls that fail in bursts, because the pieces that usually get bolted on separately, a retry loop, a circuit breaker, a concurrency cap and a bulkhead, are all policies against the same executor and compose without nesting callbacks. Two details are worth knowing before you adopt it.
Can I use it commercially?
Yes. MIT 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 7 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 October 7, 2026, and from our analysis. They are not legal advice.

Editorial analysis

One executor, many policies

The README states the design in one sentence: the library works by wrapping functions with one or more resilience policies, which can be combined and composed as needed. That sentence is the whole architecture, and it is the reason this library is worth a look rather than just another retry helper.

Because every policy attaches to the same executor, the usual alternative, nesting a retry loop inside a breaker closure inside a timeout context, collapses into a flat composition. That has two consequences worth naming. Policies apply in an order you control rather than an order implied by how deeply you nested them. And a policy such as a fallback does not need to know whether it is wrapping a retried call or a fresh one.

The top-level files in the tree support that reading. There is `executor.go`, `execution.go`, `events.go`, `result.go`, `policy.go` and `doc.go` at the root, plus an `internal/` directory and a `policy/` directory. So the execution machinery is a small number of files and the policies are packages behind one interface.

The library is licensed MIT, attributed to Jonathan Halterman and contributors, and the last push was on 2026-08-16, the same day as the v0.9.7 tag. It has 2,254 stars, 47 forks and 24 open issues, and is not archived.

Nine policies in three groups

The README groups the policies, and the grouping is a useful hint at how they compose.

Failure handling covers Retry and Fallback. Load limiting covers Circuit Breaker, Adaptive Limiter, Adaptive Throttler, Bulkhead, Rate Limiter and Cache. Time limiting covers Timeout and Hedge.

Each name is a directory in the tree, which confirms there is no bundling of several into one package. The directories are `adaptivelimiter/`, `adaptivethrottler/`, `budget/`, `bulkhead/`, `cachepolicy/`, `circuitbreaker/`, `common/`, `fallback/`, `hedgepolicy/`, `internal/`, `policy/`, `priority/`, `ratelimiter/`, `retrypolicy/` and `timeout/`.

Two names in that listing are worth pausing on because they are not in the README's list of policies. There is a `budget/` directory and a `priority/` directory. A budget package in a resilience library suggests expressing a system-wide limit, such as allowing only a percentage of calls to be retried across the process, rather than a per-call one. That is a different and more ambitious scope than most libraries in this category offer. A priority package suggests request ordering or prioritization under contention, which pairs naturally with the bulkhead and limiter policies.

Neither is documented in the README beyond what the directory names imply, so the docs site is the only place either is explained.

How the adaptive limiter differs from a fixed rate limiter

The rate limiter is the one most Go developers already understand. The adaptive limiter is the more interesting policy, and its two names suggest different behaviours.

The dependency list in `go.mod` explains a lot of the design. The module requires `github.com/bits-and-blooms/bitset v1.24.4` and `github.com/influxdata/tdigest v0.0.1`, alongside grpc and protobuf packages. A t-digest structure is a streaming approximation of a distribution, and it is the standard way to hold approximate latency percentiles without keeping every sample. So the adaptive limiter is measuring latency as a distribution and deriving its concurrency limit from that, which is a materially different mechanism from counting tokens over time.

The repository topics confirm the split: `adaptive-limiter` and `adaptive-throttler` appear alongside `rate-limiter`, `circuit-breaker`, `bulkhead`, `cache`, `fallback`, `hedge`, `retry`, `timeout`, `resilience` and `resiliency-patterns`.

The release notes show the adaptive limiter still evolving. v0.9.5 added `MaxLimitFactorDecay`, allowing the limit's headroom to vary relative to inflights. v0.9.6 added `WithMaxLimitStabilizationWindow` to support stabilization windows that mitigate fluctuating limits when setting the max limit, and `WithMaxLimitFunc` to allow the max limit to be configured based on current inflights. That same release changed an API: `WithMaxLimitFactorDecay` now expects a second parameter, `minLimitFactor`.

The release notes read like a bug list for concurrency code

The three most recent releases are worth reading in full, because they describe the failure modes this kind of library actually has.

v0.9.7 fixed three issues. `failsafegrpc.NewUnaryClientInterceptor` should preserve per-request contexts. Budgets should correctly threshold against min concurrency. An exceeded budget should not cause hedges to fail. It also added dynamic delay support for hedge policies.

v0.9.6 fixed avoiding leaking child contexts when an executor context is configured.

That pattern is instructive. The bugs are about context lifetime, about a limit thresholding against the wrong baseline, and about one policy interacting badly with another. Those are exactly the bugs you would expect in a library that composes several stateful policies over the same execution, and they are also the bugs you would inherit if you built this yourself on top of `context.Context`.

The gRPC interceptor is mentioned by name, which implies HTTP has an equivalent. The tree confirms it with `failsafegrpc/` and `failsafehttp/` directories, plus an `examples/` directory holding `cache_test.go` and `http_test.go`. So the transport integrations exist, and the examples are executable tests rather than documentation snippets.

A `CHANGELOG.md` and a `VERSIONING.md` are both present at the root, so the release notes in the GitHub releases are a convenience rather than the only record.

The build tooling shows what the maintainers actually run

The `Makefile` is short enough to read in full, and it is more informative about the project's working habits than the README is.

Build and test are the two obvious targets:

bash
go build ./...
bash
go test -race ./...

Race detection is the interesting part. For a library whose policies coordinate concurrent state inside an executor, running the suite under the race detector is not optional politeness.

The default test target does something more specific. It runs `gotestsum` over the package list with `examples`, `policytesting` and `testutil` filtered out:

bash
go run gotest.tools/gotestsum@latest `go list ./... | grep -vE 'examples|policytesting|testutil'`

That one line tells you two things. The examples are written as tests and are excluded from the main suite, which is why `examples/http_test.go` and `examples/cache_test.go` are test files rather than programs. And a package called `policytesting` exists, presumably shared test helpers for policy authors.

Linting runs `golangci-lint` with errcheck and unused disabled:

bash
golangci-lint run -D errcheck,unused

The default goal is `help`, which greps the Makefile for targets with comments in order to print a menu. The `check` target runs fmt and test and then `go mod tidy`, which is a sensible pre-commit gate.

`go.mod` requires Go 1.21.

What the README deliberately does not document

The README is short and it points at failsafe-go.dev for usage info, docs and additional resources. Under the Usage heading, that link is the entire section. No policy is described, no code example appears, and no configuration option is named.

That is a deliberate choice rather than an unfinished README. For a library whose value is in how policies compose, a quick start that shows one policy in isolation would misrepresent it. But it does mean the README alone cannot answer the question a new user actually has, which is what order the policies go in.

The badges carry some of that load. There is a build status badge pointing at a test workflow, a codecov badge with coverage graph, an MIT licence badge and a Godoc badge. The codecov link is the one to click if you want a sense of test depth, and the Godoc badge is the practical alternative to the website for reading an API surface.

For a library at v0.9.7 with 24 open issues and active work on adaptive limiter behaviour, the changelog and release notes are likely more informative than the site for understanding recent changes. The README's restraint makes sense once you have seen that the substance lives in the docs.

Editorial conclusion

failsafe-go earns its place when a service makes calls that fail in bursts, because the pieces that usually get bolted on separately, a retry loop, a circuit breaker, a concurrency cap and a bulkhead, are all policies against the same executor and compose without nesting callbacks. Two details are worth knowing before you adopt it. The budget package is the one that turns a system-wide goal into code, and it is only visible from the directory listing rather than the README. And the adaptive limiter is genuinely adaptive, computing its limit from measured latency percentiles via tdigest, which means it needs traffic before it does anything useful. Go 1.21 or newer, read the policy pages on failsafe-go.dev, and start with a circuit breaker and a timeout.

Frequently asked questions

How can I implement a circuit breaker in Golang?

failsafe-go ships a Circuit Breaker policy in the `circuitbreaker` package. You build one with its builder, attach it to a failsafe executor together with any other policies such as Retry or Fallback, and run your call through the executor. Policy order is yours to choose rather than implied by nesting.

Which resilience policies does failsafe-go include?

The README lists Retry and Fallback for failure handling, Circuit Breaker, Adaptive Limiter, Adaptive Throttler, Bulkhead, Rate Limiter and Cache for load limiting, and Timeout and Hedge for time limiting. The repository tree also shows budget and priority packages that the README's list does not cover.

What is the difference between the adaptive limiter and the rate limiter?

The rate limiter counts over time, in the way you would expect. The adaptive limiter derives its concurrency limit from measured latency, and `go.mod` pulls in `influxdata/tdigest`, a streaming approximate quantile structure, which is how it holds latency percentiles. v0.9.6 added `WithMaxLimitStabilizationWindow` and `WithMaxLimitFunc` to it.

Does failsafe-go have HTTP and gRPC integrations?

Yes. The tree has `failsafehttp` and `failsafegrpc` directories, and v0.9.7 fixed a bug in `failsafegrpc.NewUnaryClientInterceptor` where per-request contexts were not preserved. The examples directory contains `http_test.go` and `cache_test.go`, written as tests.

Official sources

  1. failsafe-go/failsafe-go on GitHub
  2. License: MIT
  3. Project website
  4. README
  5. Releases
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/failsafe-go-failsafe-go.svg)](https://hysenlabs.com/projects/failsafe-go-failsafe-go)