MCPcopy Index your code
hub / github.com/cinar/resile

github.com/cinar/resile @v1.0.6

Chat with this repo
repository ↗ · DeepWiki ↗ · release v1.0.6 ↗ · + Follow
351 symbols 1,298 edges 59 files 139 documented · 40%
What it actually does AI analysis from the code graph — generated when you open this
loading…
README

Resile: Ergonomic Execution Resilience for Go

Go Reference License Build Status Codecov Go Report Card YouTube Dev.to

Resile is a resilience and retry library for Go, inspired by Python's stamina. It provides a type-safe, ergonomic, and highly observable way to handle transient failures in distributed systems.


See Resile in Action

Resile Demo Video

Subscribe to our YouTube channel for deep dives and tutorials.


The "Aha!" Snippet

Resile allows you to compose complex resilience strategies with a single, type-safe call. No interface{} casting, no reflection—just clean Go.

user, err := resile.Do(ctx, func(ctx context.Context) (*User, error) {
    return client.GetUser(ctx, id)
},
    resile.WithBulkhead(10),            // Max 10 concurrent requests
    resile.WithCircuitBreaker(cb),      // Stop if failure rate > 50%
    resile.WithRetry(3),                // 3 attempts with AWS Full Jitter
    resile.WithTimeout(1*time.Second),   // Each attempt max 1s
    resile.WithFallback(func(ctx context.Context, err error) (*User, error) {
        return cache.Get(id), nil       // Return stale data on failure
    }),
)

Table of Contents


Installation

go get github.com/cinar/resile

Requires Go 1.24+ (uses generics and errors.Join).


Why Resile?

In distributed systems, transient failures are a mathematical certainty. Resile simplifies the "Correct Way" to retry: - AWS Full Jitter: Uses the industry-standard algorithm to prevent "thundering herd" synchronization. - Adaptive Retries: Built-in token bucket rate limiting to prevent "retry storms" across a cluster. - Generic-First: No interface{} or reflection. Full compile-time type safety. - Context-Aware: Strictly respects context.Context cancellation and deadlines. - Zero-Dependency Core: The core resile, circuit, and chaos packages depend only on the Go standard library. Telemetry adapters (telemetry/) are opt-in. - Opinionated Defaults: Sensible defaults (5 attempts, exponential backoff). - Chaos-Ready: Built-in support for fault and latency injection to test your resilience policies.


Articles & Tutorials

Want to learn more about the philosophy behind Resile and advanced resilience patterns in Go? Check out these deep dives:

Also, check out our Dev.to space for more articles and discussions.


Examples

The examples/ directory contains standalone programs showing how to use Resile in various scenarios:


API Reference

Function Signature Description
Do[T] (ctx, action, ...Option) (T, error) Retry an action that returns a value.
DoErr (ctx, action, ...Option) error Retry an action that returns only an error.
DoState[T] (ctx, action, ...Option) (T, error) Like Do, with access to RetryState.
DoErrState (ctx, action, ...Option) error Like DoErr, with access to RetryState.
DoHedged[T] (ctx, action, ...Option) (T, error) Speculative retries for tail latency.
DoErrHedged (ctx, action, ...Option) error Error-only hedging variant.
DoStateHedged[T] (ctx, action, ...Option) (T, error) Stateful hedging (e.g., endpoint rotation).
DoErrStateHedged (ctx, action, ...Option) error Error-only stateful hedging.
New (...Option) Retryer Create a reusable Retryer instance.
NewPolicy (...Option) *Policy Create a composed resilience policy.
NewStateMachine[S,D,E] (S, D, TransitionFunc, ...Option) *StateMachine Create a resilient state machine.
FatalError (error) error Mark an error as non-retryable.
WithTestingBypass (context.Context) context.Context Skip all backoff delays in tests.
InjectDeadlineHeader (ctx, Header, string) Propagate deadline to outgoing requests.

Resilience Cookbook

1. Simple Retries

The Problem: A database connection or network request might fail intermittently due to transient blips.

The Recipe: Retry a simple operation that only returns an error. If all retries fail, Resile returns an aggregated error containing the failures from every attempt.

err := resile.DoErr(ctx, func(ctx context.Context) error {
    return db.PingContext(ctx)
})

2. Value-Yielding Retries (Generics)

The Problem: Fetching data from a microservice needs to be resilient and type-safe without boilerplate casting.

The Recipe: Fetch data with full type safety. The return type is inferred from your closure.

// val is automatically inferred as *User
user, err := resile.Do(ctx, func(ctx context.Context) (*User, error) {
    return apiClient.GetUser(ctx, userID)
}, resile.WithMaxAttempts(3))

3. Request Hedging (Speculative Retries)

The Problem: Long-tail latency (the 99th percentile) slows down your entire system even when most requests are fast.

The Recipe: Speculative retries reduce tail latency by starting a second request if the first one doesn't finish within a configured HedgingDelay. The first successful result is used, and the other is cancelled.

// For value-yielding operations
data, err := resile.DoHedged(ctx, action, 
    resile.WithMaxAttempts(3),
    resile.WithHedgingDelay(100 * time.Millisecond),
)

// For error-only operations
err := resile.DoErrHedged(ctx, action,
    resile.WithMaxAttempts(2),
    resile.WithHedgingDelay(50 * time.Millisecond),
)

Stateful hedging variants are also available for endpoint rotation with speculative retries:

data, err := resile.DoStateHedged(ctx, func(ctx context.Context, state resile.RetryState) (string, error) {
    url := endpoints[state.Attempt % uint(len(endpoints))]
    return client.Get(ctx, url)
}, resile.WithHedgingDelay(100 * time.Millisecond))

Read more: Beating Tail Latency: A Guide to Request Hedging in Go Microservices

4. Stateful Retries & Endpoint Rotation

The Problem: Retrying against the same failing endpoint is futile; you need to cycle through a list of healthy hosts.

The Recipe: Use DoState (or DoErrState) to access the RetryState, allowing you to rotate endpoints or fallback logic based on the failure history.

endpoints := []string{"api-v1.example.com", "api-v2.example.com"}

data, err := resile.DoState(ctx, func(ctx context.Context, state resile.RetryState) (string, error) {
    // Rotate endpoint based on attempt number
    url := endpoints[state.Attempt % uint(len(endpoints))]
    return client.Get(ctx, url)
})

Read more: Self-Healing State Machines: Resilient State Transitions in Go

5. Handling Rate Limits (Retry-After)

The Problem: Downstream services may

Extension points exported contracts — how you extend this code

Instrumenter (Interface)
Instrumenter defines the lifecycle hooks for monitoring retry executions. It is a zero-dependency interface to allow cus [4 …
telemetry.go
RNG (Interface)
RNG defines the interface for randomization, allowing for mock implementations in tests. [4 implementers]
chaos/injector.go
Backoff (Interface)
Backoff defines the interface for temporal distribution of retries. [3 implementers]
backoff.go
RetryAfterError (Interface)
RetryAfterError is implemented by errors that specify how long to wait before retrying. This is commonly used with HTTP [3 …
policy.go
Header (Interface)
Header defines an interface for injecting metadata into outgoing requests. This allows Resile to remain agnostic of the [1 …
propagation.go
Retryer (Interface)
Retryer defines the interface for executing actions with resilience. [1 implementers]
retry.go
TransitionFunc (FuncType)
TransitionFunc defines the signature for a state transition function. It takes the current state, data, and event, and r
statemachine.go
Option (FuncType)
Option defines a functional option for configuring a retry execution.
options.go

Core symbols most depended-on inside this repo

WithMaxAttempts
called by 62
options.go
Error
called by 44
retry.go
DoErr
called by 26
retry.go
Execute
called by 24
circuit/breaker.go
WithBaseDelay
called by 21
options.go
NewPolicy
called by 20
policy.go
DefaultConfig
called by 20
retry.go
State
called by 19
circuit/breaker.go

Shape

Function 178
Method 112
Struct 40
TypeAlias 10
Interface 7
FuncType 4

Languages

Go100%

Modules by API surface

retry.go43 symbols
retry_test.go33 symbols
options.go27 symbols
circuit/breaker.go24 symbols
policy.go16 symbols
chaos_test.go11 symbols
deadline_propagation_test.go10 symbols
chaos/injector.go9 symbols
examples/sql/main.go8 symbols
chaos/injector_test.go8 symbols
adaptive_concurrency.go8 symbols
telemetry/resileslog/slog_test.go7 symbols

Datastores touched

mydbDatabase · 1 repos

For agents

$ claude mcp add resile \
  -- python -m otcore.mcp_server <graph>

⬇ download graph artifact