Download the PHP package gohany/circuitbreaker without Composer

On this page you can find all versions of the php package gohany/circuitbreaker. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.

FAQ

After the download, you have to make one include require_once('vendor/autoload.php');. After that you have to import the classes with use statements.

Example:
If you use only one package a project is not needed. But if you use more then one package, without a project it is not possible to import the classes with use statements.

In general, it is recommended to use always a project to download your libraries. In an application normally there is more than one library needed.
Some PHP packages are not free to download and because of that hosted in private repositories. In this case some credentials are needed to access such packages. Please use the auth.json textarea to insert credentials, if a package is coming from a private repository. You can look here for more information.

  • Some hosting areas are not accessible by a terminal or SSH. Then it is not possible to use Composer.
  • To use Composer is sometimes complicated. Especially for beginners.
  • Composer needs much resources. Sometimes they are not available on a simple webspace.
  • If you are using private repositories you don't need to share your credentials. You can set up everything on our site and then you provide a simple download link to your team member.
  • Simplify your Composer build process. Use our own command line tool to download the vendor folder as binary. This makes your build process faster and you don't need to expose your credentials for private repositories.
Please rate this library. Is it a good library?

Informations about the package circuitbreaker

CI codecov

Gohany Circuitbreaker

This project is a practical, general-purpose circuit breaker library for PHP (>=7.4).

But a circuit breaker is only the first chapter.

Over time, production systems grow a whole resilience vocabulary: circuit breaking, careful probing, retries, concurrency limits, fairness between callers, operational overrides, and observability. This repository implements that vocabulary as small, composable primitives.

If you only remember one sentence, remember this:

You are not “calling a dependency”. You are negotiating with it.

The negotiation is driven by history (what happened recently), by current state (open/half-open/closed), by per-request context (tenant, endpoint, risk), and sometimes by operational reality (incident response overrides).

This README is intentionally long-form. It starts with the concepts, then gives an explicit feature catalog, and then expands into realistic usage examples.


Table of contents


Why circuit breakers

Operations fail in messy ways:

If callers keep attempting a failing action during an outage, you typically get cascading failures:

A circuit breaker reduces blast radius by:


Core concepts

Circuit breakers typically have three states:

closed

Normal mode: calls are allowed. Failures are tracked.

open

Fail-fast mode: calls are blocked for openDurationMs.

half_open

Probe mode after the open duration expires:

A key knob you’ll see in this project:

This prevents “flapping” (a dependency that briefly looks healthy but collapses again).


Concepts (extended guide)

This section is the “novel” part: a guided walk through the moving parts, and why you might use each.

Keys, dimensions, and context

The unit of protection is a CircuitKey.

The per-call “who/what/why” is a CircuitContext.

CircuitKey is where state lives. CircuitContext is what you know about this request right now.

In storage-backed implementations, a circuit key needs a stable identifier. This project provides CircuitKey::id() for that purpose.

Policies, outcomes, and signals

CircuitPolicyInterface answers two questions:

1) Should I allow this call right now? (decide(...) → PolicyDecision) 2) What should happen after we observe the outcome? (onOutcome(...) → TransitionPlan)

The project’s policies operate on two kinds of inputs:

Signals are how you convert messy reality into a vocabulary your policy understands. For example: timeout, http_5xx, fraud_suspected, rate_limited.

The conversion is done by OutcomeClassifierInterface.

State stores and history stores

There are two storage responsibilities:

This repo includes multiple storage backends under src/Store/*:

Probe gating (half-open concurrency)

When a circuit transitions to half_open, you typically want to probe carefully:

That is what the ProbeGateInterface does.

The core breaker (Core\CircuitBreaker) can acquire a probe gate permit when a decision indicates requiresProbeGate. Implementations exist for in-memory, Redis, and PDO.

Operational overrides

Production systems need a manual “steering wheel” during incidents.

Overrides let you force behaviour without redeploying code:

Overrides are implemented via OverrideDeciderInterface and the Redis implementation lives under src/Override/Redis/*.

Retries (circuit-aware)

Retries without a circuit breaker can amplify an outage. Retries without context can also hide persistent failures.

This project integrates with gohany/rtry under src/Integration/Rtry/* so retries can be:

Bulkheads (concurrency limits)

A circuit breaker decides whether you may call. A bulkhead decides how many callers may call concurrently.

This repo includes bulkheads under src/Bulkhead/*:

The “fair queue” bulkhead is designed for shared resources like databases:

Resilience pipeline

When you start composing these primitives, you eventually want a single “do the safe thing” entry point.

ResiliencePipeline is a minimal middleware chain (see src/Resilience/*) that can wrap an operation with:

The pipeline is intentionally small: you can add/remove pieces without rewriting your business code.

Observability

There are two observability styles in the repo:

Sanity tooling

There are scripts intended for humans and CI to validate wiring:

They are not required for runtime usage, but they are useful when you first integrate the library.


Feature catalog

This is the explicit list of “what this project now does”, grouped by concept.

Circuit breaker (core)

HTTP defaults (PSR-18)

Bulkheads

Stores

Probe gating

Operational override & administration (Redis)

Retry integration

Resilience pipeline

Observability


Installation


Quickstart

At minimum you: 1) Create a policy (which defines what a "failure" is and when to trip) 2) Create a circuit breaker (with a state store) 3) Wrap your risky operation

Basic Example (Any Operation)

Notes:


HTTP usage

Because HTTP is the most common use case, we provide a PSR-18 client decorator, multi-circuit coordination, and composable key-building helpers.

For detailed usage patterns, including the PSR-18 HTTP Client Decorator, custom key/context building, and full wiring examples, please refer to:

👉 examples.md

Recommended starting points:


Alternative: wrap a single call

For one-off risky operations:


Choosing a circuit key

A circuit key answers: what should share a fate?

Good defaults:

Rule of thumb:


Default implementations & Examples

To get started quickly, this library provides several "sane" defaults:

For detailed usage patterns and wiring examples, see examples.md.


Default HTTP policy

This project ships an HTTP-oriented base policy/config:

A typical HTTP policy treats these as failures:

Often not counted as dependency failures:

Key knobs:


Customizing default policies

Config subclasses (recommended)

This project intentionally avoids “constructor-loop overrides.” Instead, prefer small config subclasses with explicit defaults.

Example:

Usage:

Why this is good:


Policy subclasses

Use a policy subclass when “what counts as failure” differs.

Example intent:

The pattern is: centralize classification in your OutcomeClassifierInterface and keep per-service differences in config.


Fraud stays separate

Fraud vendors often have domain semantics (scores, review/hold flows) that do not belong in the base HTTP rules.

Keep layers clean:

You still circuit-break fraud calls, you just avoid mixing domain rules into generic HTTP logic:


Retry + Circuit Breaker

Retries and circuit breakers solve different problems:

Used incorrectly, retries amplify outages. Used correctly, retries reduce tail latency and smooth over transient blips.

Circuit-aware retries (deep integration)

This project integrates deeply with gohany/rtry to ensure retries are safe.

When using the RtryRetryExecutor, it automatically applies a CompositeDecider that checks:

  1. Outcome classification: Does the circuit breaker’s OutcomeClassifierInterface think the error is a transient_failure?
  2. Circuit health: Is the circuit still allowed according to the current state and policies (e.g., fraud overrides, manual circuit trips)?

If the circuit is denied mid-retry (e.g., a tenant is blocked for fraud while a network request is retrying), the executor will stop immediately and propagate the failure.

Extension points:

Easy expansion from rtry to Circuit Breaker

If you are already using gohany/rtry, you can bring your existing policies and deciders into the circuit breaker seamlessly. The RtryRetryExecutor will respect your custom deciders:

The breaker will only retry if:

  1. Your MyCustomDecider says YES.
  2. The circuit breaker's classifier says the error is transient_failure.
  3. The circuit is still healthy (not opened/tripped mid-retry).

Unified retryAfterMs calculation

When a circuit is open, the breaker tells the caller how long to wait via retryAfterMs. To ensure consistency between your circuit breaker and retry strategies, AbstractHttpCircuitPolicy can dynamically calculate this value using your rtry policies.

By implementing RetrySpecProviderInterface in your policy (or using the default provided hooks), the circuit breaker will:

  1. Check if the current policy has a RetrySpec for the circuit.
  2. If so, it takes the maximum of:
    • The remaining time until the circuit technically "expires" its open state.
    • The startAfterMs delay defined in your rtry policy.

This prevents the circuit breaker from allowing a "half-open" probe attempt earlier than your retry policy would even allow the first retry.

Why composition order matters

Recommended composition:

Circuit breaker wraps the overall operation. Retries happen inside.
The breaker records one success/failure for the operation, not for each attempt.

Conceptually:

Avoid:

Also: when the circuit is open, do not retry. Fail fast.


Sane retry defaults

A good default posture for idempotent HTTP operations:

Do not retry most 4xx.


Idempotent vs non-idempotent retries

Idempotent example: GET (safe to retry)

Non-idempotent example: POST (dangerous to retry)

Only retry if you have a strong idempotency mechanism (idempotency key, request token, etc.).

Conservative posture for writes:


Baking in retry policies

If you want “sane retry policies” baked into this project (not required, but often desirable), keep it minimal and composable.

Suggested building blocks:

1) RetryPolicy (numbers + backoff behavior) 2) RetryDecider (what is retryable?) 3) Retryer (executes attempts + sleeps)

Suggested defaults to ship:

Then usage looks like:

Implementation notes:


Picking good numbers

Starting points:

General external HTTP dependencies

Payments / fraud vendors

Internal services

If you’re unsure: start conservative and tune with real metrics.


Testing recommendations

At minimum, validate these transitions:

1) closed → open

2) open blocks calls

3) open → half_open

4) half-open failure threshold

5) half_open → closed

Also test classification rules:

For non-production test environments where you want full breaker stats/state transitions but do not want requests to be hard-blocked, opt-in per call via context attribute:

This keeps decisioning and outcome recording active, but bypasses the final deny throw (CircuitDeniedException). Keep this disabled in production.


Exceptions

The library uses a hierarchy of exceptions that all extend \RuntimeException, making them easy to catch while remaining compatible with standard PHP error handling.


FAQ

Should I retry when the circuit is open?

No. If the circuit is open, fail fast immediately.

Should circuits be per-host or per-endpoint?

Start with service + capability keys (payments:charges). Split further only if needed.

Where should I wrap the breaker?

As close to the dependency boundary as possible:

How do I keep fraud separate?

Use separate keys/config/policies for fraud: fraud:*. Don’t put domain semantics into base HTTP rules.



All versions of circuitbreaker with dependencies

PHP Build Version
Package Version
Requires php Version >=7.4
psr/clock Version ^1.0
psr/http-client Version ^1.0
psr/http-message Version ^1.0 || ^2.0
gohany/rtry Version ^1.0
ext-json Version *
Composer command for our command line client (download client) This client runs in each environment. You don't need a specific PHP version etc. The first 20 API calls are free. Standard composer command

The package gohany/circuitbreaker contains the following files

Loading the files please wait ...