Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Fault Tolerance Bundle Laravel Package

micro-module/fault-tolerance-bundle

A fault-tolerance bundle for PHP/Laravel apps that adds circuit breakers, retries, timeouts, and fallback handling to unreliable service calls. Configure policies per service and keep failures from cascading through your application.

View on GitHub
Deep Wiki
Context7

Getting Started

This is a low-traffic package (0 stars, 0 dependents, single release in Sept 2025), so treat the source as the documentation. Budget 30–45 minutes to read it before wiring it into anything production-facing.

Install and inspect:

composer require micro-module/fault-tolerance-bundle
composer show micro-module/fault-tolerance-bundle   # confirm version + autoload namespace

Where to look first, in order:

  1. composer.json — check require for symfony/* vs illuminate/*. The name says bundle (Symfony terminology), so confirm whether a Laravel ServiceProvider is shipped or whether you must register services manually in config/app.php / bootstrap/providers.php.
  2. The service/attribute classes — look for the retry, circuit-breaker, timeout, and fallback entry points. Note the namespace root; it is likely MicroModule\FaultTolerance\... or similar.
  3. Default config — any *.yaml, *.php, or Resources/config/ directory. Copy it into config/fault-tolerance.php if the package supports publishing; otherwise wrap the defaults in your own config file.
  4. Tests — with zero dependents this is your best behavioural spec. The package's own test suite shows intended call signatures more reliably than the README.

First use case: wrap a single outbound call to a flaky downstream microservice. Something like a retry (3 attempts, exponential backoff) with a hard timeout and a cached fallback response. Do not start by wrapping every HTTP client — pick one endpoint, observe behaviour in staging, then roll out. Verify the circuit breaker actually opens by pointing it at a black-hole host, not by trusting the README.

If no Laravel provider exists, create a thin wrapper service in your app that resolves the package classes from the container, so you can swap the implementation later without touching call sites.

Implementation Patterns

Decorator around the HTTP client. The cleanest integration is a Laravel HTTP client macro or a small FaultTolerantClient class that wraps Http::...->send(). Keep the package's retry/breaker concerns out of your controllers and out of your domain services; put them in one adapter.

Retry for idempotent reads, breaker for everything. Retries on GET are safe; retries on POST need an idempotency key or you will double-charge customers. The circuit breaker is the pattern that protects you from a dead dependency, so apply it more broadly than retries.

Fallback as an explicit return type. If a fallback returns a cached/stale payload, make it the same DTO the happy path returns — otherwise callers end up with null checks scattered through the codebase. A Result-style wrapper ({ ok, data, degraded: true }) makes degraded mode visible in logs and metrics.

Queue jobs. Wrap the dispatch site, not the job body, if you want the breaker to shed load before jobs pile up in Redis. Wrapping inside handle() only retries work the queue already retries — you get multiplicative retries and a thundering herd on recovery. If you must wrap the job, set $tries = 1 on the job and let the package own the retry policy.

Shared breaker state via cache. Circuit breakers only work if every worker sees the same state. Configure the state store to Redis (or your shared cache), keyed by downstream service name plus environment. Array/file cache makes the breaker per-process and effectively decorative.

Composition order matters. Timeout outermost, then breaker, then retry, then the actual call. Reversing timeout and retry means a 3-retry budget can consume 3× your timeout. Reversing breaker and retry means retries bypass the open circuit.

Health checks and metrics. Emit a counter for breaker.opened, retry.attempt, fallback.used per downstream. A breaker that opens silently is worse than no breaker — you lose the signal that a dependency is failing.

Gotchas and Tips

  • It is a Symfony bundle by name. Verify Laravel compatibility explicitly. If there is no Illuminate\Support\ServiceProvider, DI, config publishing, and php artisan config:cache semantics all need manual handling — and cached config means config changes require php artisan config:clear.
  • Zero dependents means zero field reports. Pin the exact version in composer.json, and read the diff before every bump. Do not use ^ constraints on a package with one release and no downstream users.
  • Half-open thundering herd. When the breaker transitions to half-open after the cooldown, all workers may probe simultaneously and re-kill the dependency. Look for a probe-limit setting; if absent, add jitter to the cooldown or gate the probe behind a lock.
  • Guzzle timeouts are two settings. connect_timeout and timeout are distinct. A package-level "timeout" may map to only one. Set both at the HTTP client level as a backstop.
  • PHP max_execution_time is not a timeout. It is a fatal error, not an exception — your fallback will not run. Keep the package timeout well under it, and under your queue worker's --timeout.
  • Retry budget on recovery. Exponential backoff alone is not enough; add a cap and jitter, or every service recovers into a synchronized retry storm.
  • State leakage in tests. Reset breaker state between tests (RefreshDatabase does not touch Redis). Otherwise a test that trips a breaker poisons subsequent tests, and failures look random and order-dependent.
  • Testing degraded paths. You need a way to force "breaker open" and "retry exhausted" without actually waiting. Look for a clock/state injection point; if the package hard-codes sleep(), Carbon::setTestNow will not help and your test suite will get slow fast.
  • Extension points to hunt for: a failure predicate (do 4xx responses count as failures? usually only 5xx and connection errors), a custom state store, and events you can listen to for logging. If the failure predicate is not configurable, a stream of 404s from a misconfigured URL will trip your breaker and you will spend an afternoon confused.
  • Log context. Tag every retry/breaker log line with the downstream name, attempt number, and correlation ID. Without this, breaker noise is indistinguishable from application errors.
  • Fallback failure modes. A fallback that itself throws turns a degraded response into a 500. Wrap the fallback in its own try/catch and return the empty-but-valid DTO.
  • Consider the alternative. For a single outbound dependency, 40 lines of Guzzle middleware plus a Redis counter gives you retry and breaker semantics you fully understand and can debug at 3am. Adopt the package where it saves real work — multiple dependencies, consistent configuration, shared metrics — not for one call site.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
coleus/frame
thtg88/journalism
filagora/filagora-ai-forums
rlacerda83/query-parser
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings