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 Laravel Package

micro-module/fault-tolerance

Fault tolerance utilities for Laravel micro-modules: add retries, circuit breakers, timeouts, and graceful fallbacks around service calls so failures in one module don't cascade. Configurable policies and framework-native integration keep resilient code simple.

View on GitHub
Deep Wiki
Context7

Getting Started

composer require micro-module/fault-tolerance

Then, in order:

  1. Read the source before the README. With zero stars and zero dependents, the package has no community-vetted documentation trail. Start in src/ and look for the service provider (FaultToleranceServiceProvider or similar), the config file (config/fault-tolerance.php), and any facade or manager class. Those three files tell you the entire public surface area in about ten minutes.
  2. Publish the config (assuming standard Laravel packaging):
    php artisan vendor:publish --provider="MicroModule\\FaultTolerance\\FaultToleranceServiceProvider"
    
    If no publish tag exists, copy the config file manually and register it — the package is new enough that packaging conventions may not be fully baked.
  3. Confirm the package registers. Run php artisan about and check the providers list, or php artisan tinker and resolve the main class from the container. Given opportunity: 27.8 and no dependents, auto-discovery may or may not be wired correctly.

First use case

The canonical entry point for a fault-tolerance library is wrapping an outbound call to a sibling microservice — payment, inventory, notifications — that you don't control. Start with the single flakiest downstream dependency in your system and wrap it:

use MicroModule\FaultTolerance\Facades\FaultTolerance;

$response = FaultTolerance::for('inventory-service')
    ->retry(3, backoff: 200)
    ->timeout(2.0)
    ->circuitBreaker(threshold: 5, cooldown: 30)
    ->call(fn () => Http::get('https://inventory.internal/stock/42'));

if ($response->failed()) {
    // degraded path
}

Adapt the fluent API to whatever the actual class exposes — the shape (named guard, retry, timeout, breaker, call) is the near-universal convention for this class of library. If the package instead centers on middleware for inbound requests, use that first: register the middleware on a single route group and watch logs for a day before widening it.

Implementation Patterns

Per-downstream guard configuration. Define one named guard per external service in config/fault-tolerance.php, each with its own threshold, timeout, and cooldown. Sharing a single global breaker across all downstreams is the most common mistake — a slow email provider should not trip the breaker protecting your payment calls.

Retry only idempotent operations. Wrap GETs, PUTs, and DELETEs freely. For POSTs, require an idempotency key in the request before you allow retries. The library cannot know your semantics, so this is on you.

Fallback as a first-class path. Pair every guarded call with an explicit degraded response — cached value, stale data, queue-and-forget, or a user-visible "temporarily unavailable." A circuit breaker without a fallback just converts a timeout into a fast exception, which is better for latency but not for UX.

Bulkhead by module. If the package supports concurrency limits, cap how many in-flight calls each micro-module can make to each dependency. In a modular monolith with several "modules" talking to the same service, one chatty module can starve the rest.

Instrument from day one. Emit a metric or structured log line on every state transition (closed → open → half-open → closed) and on every retry attempt. Attach the guard name and the downstream host as labels. Without this you will discover a permanently-open breaker only when a user complains.

Layer with your HTTP client. Register the guard around Http:: calls, not inside a job's handle() body, so retries stay within a single request lifecycle and you don't accidentally retry an entire queued job.

Test the open state explicitly. Provide a way (test helper, fake clock, or a public forceOpen()) to put a guard into the open state and assert that the fallback path returns the degraded response. Also assert the half-open probe behavior — a breaker that never closes again is worse than no breaker.

Queues as the safety valve. For non-user-facing work, the most robust pattern is: try the guarded call, and on breaker-open, dispatch a job with a delay instead of failing. This turns "downstream is down" into "downstream is slow" from the user's perspective.

Gotchas and Tips

  • Stateful breakers need shared storage. If the package persists breaker state to the Laravel cache, the driver matters enormously. array resets on every request (useless); file doesn't work across multiple pods; use Redis or database. Check config/cache.php and the package's store config before trusting it in any horizontally-scaled deployment.
  • Timeouts multiply with retries. retry(3) plus timeout(2.0) is a potential 6+ seconds of wall time, which will blow past PHP's max_execution_time or your load balancer's idle timeout. Budget total latency, not per-attempt latency.
  • config:cache in production. If you publish config and later change breaker thresholds, php artisan config:cache in your deploy script will serve stale values until re-run. Make threshold changes part of a deploy, not a live edit.
  • Don't swallow exceptions in the fallback. A fallback that returns null silently hides outages. Log at warning with the guard name and the original exception before returning degraded data.
  • Zero dependents is a real signal. Pin the exact version (or a narrow ~ constraint) in composer.json. Read the changelog between releases; with a package this young, minor bumps may include behavior changes to thresholds or state storage. Consider vendoring or forking if the surface area you use is small.
  • Reset state between tests. A breaker that tripped in one feature test will leak into the next if state is cached. Add a RefreshDatabase-equivalent teardown or a package-provided reset helper in your base TestCase.
  • Extension points to look for: a custom failure predicate (so a 4xx doesn't count as a failure), a custom state store, and lifecycle events (CircuitOpened, CircuitClosed, RetryAttempted). The events are the cheapest way to hook in alerting without patching the package.
  • Watch for the "retry the fallback" bug. If the fallback itself calls another guarded service, and that service is also down, you can nest retries recursively. Keep fallbacks to in-process computations, cache reads, or queue dispatches.
  • Last release was 2025-11-14 — recent enough that you should check the GitHub issue tracker for open reports before adopting. With zero stars, issues may go unanswered for a long time; budget for self-support.
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.
elsayed85/laravel-api-exceptions
ouhssini/laravel-demo-mode
daworks/ncloud-outbound-mailer-driver
gp247/cms
ignibyte/aic-gates
nexa-merchant/blog
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
cgv/localized-resource