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

Laravel Fuse Laravel Package

harris21/laravel-fuse

Laravel Fuse adds fuzzy search to Eloquent models and collections, helping users find results despite typos. Configure searchable fields and thresholds, then run simple fluent queries for fast, relevant matches without external search services.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

Architecture fit

harris21/laravel-fuse is a circuit-breaker for Laravel that sits on the queue path, not the HTTP path: middleware gates whether a job may run, a cache-backed state machine tracks per-service health, probes (OldestJobProbe and equivalents) decide when to close an open circuit, and transition listeners plus a /fuse status page expose state. That is a good architectural fit for any Laravel estate where queue workers make outbound calls to flaky third parties (payments, KYC, shipping, email, partner APIs) and where $tries/backoff alone is too blunt — the value is stopping a queue full of retries from hammering a degraded dependency and from duplicating side effects.

The package is deliberately thin: middleware, a config file, a cache namespace, a Blade view. No database migrations, no service provider gymnastics beyond registration, no long-running daemon. That keeps it composable with Horizon, dispatchSync, and multi-queue topologies. The main architectural constraint is that state lives in the cache, so the cache is now on the critical path for job dispatch correctness — which is precisely what v0.11.0 is about.

Integration feasibility

Straightforward for a team already on Laravel queues: publish config and (optionally) views, register middleware on the relevant jobs or job base class, define per-service thresholds, register listeners, gate the status page behind existing auth middleware. Days, not weeks, for a first service.

v0.11.0 materially improves feasibility because it fixes a class of silent-misconfiguration bugs that would otherwise have burned us during rollout:

  • Dotted service names (payments.stripe) previously fell through to global defaults with no warning. Any naming convention using dots was silently unconfigured in production.
  • Missing threshold no longer yields a hard-coded 50, or 60 during 09:00–17:59 through a peak window nobody configured. Configs now resolve predictably, and peak windows can cross midnight (22 → 6), which matters for teams with offshore traffic.
  • Custom cache prefix no longer leaks state history and the ENABLED badge across apps sharing a cache.

Feasibility drops for anyone who built a custom recovery strategy that throws deliberately. That was previously a supported way to hard-stop a job; it now releases the job (except on the sync driver, where the error is still thrown). That pattern must be audited before upgrade.

Technical risk

Moderate, and mostly migration risk rather than runtime risk. The release is a net risk reduction: cache failures no longer convert a successful job into a failed one (which caused a retried job to call the external service twice — the single most expensive failure mode a circuit breaker can introduce). Reporter and listener exceptions are contained, a throwing CircuitBreakerOpened listener no longer holds the probe lock until TTL, and a successful probe now closes the circuit even when the counter write fails — that last one alone removed a 91-second recovery penalty on default OldestJobProbe settings.

Residual risks to price in:

  • Behavior change on gating errors. A cache error while deciding whether a job may run now releases the job with its release delay instead of counting toward $maxExceptions. This is the right call, but it means a persistently broken cache can produce a long release loop rather than a clean dead-letter — watch queue age, not just failure counts.
  • Threshold semantics change. Services relying on the implicit 60-at-peak now trip at default_threshold at all hours. Depending on that value, circuits may open earlier than the team's historical baselines.
  • Driver asymmetry. sync (and dispatchSync()) still throws where async releases. Any behavior assertions in tests or any synchronous internal callers need to be exercised on both paths.
  • Status page surface change. With status_page.enabled off and custom middleware, routes now 404; /fuse/data returns 503 during cache outages. Both are correct, both will trip naive uptime checks.
  • Published view drift. Teams that published the status view keep their copy and therefore will not get the red DATA UNAVAILABLE label — silently losing the outage indicator exactly when it matters.
  • Pre-1.0 versioning. v0.11.0 ships five behavior changes in a minor. Treat every minor as a review-required upgrade until a 1.0/deprecation policy exists.

Key questions

  1. What is the shipped default for default_threshold, and is there guidance for teams that were implicitly relying on the 60-during-peak behavior?
  2. Is there a stated semver/deprecation policy, and what is the path to 1.0? How many behavior changes should we expect per minor?
  3. Is circuit state (not just status-page history) namespaced under fuse.cache.prefix for multiple apps sharing one Redis? The notes only confirm the status page and kill switch.
  4. On the new "release on gating error" path, is there any backoff beyond the job's release value, or a way to surface repeated releases as an alertable signal?
  5. What is the recommended production cache backend, and what is the failure behavior under cache latency (not hard error) — timeouts on every dispatch?
  6. How are contained listener/reporter exceptions surfaced — Laravel's handler only, or an event/metric we can pipe into our observability stack?
  7. Is $tries = 0 on Fuse-gated jobs enforceable or lintable, given a release still counts as an attempt?
  8. What are the tested Laravel/PHP version bounds, and does the Carbon-everywhere change (now honoring $this->travel() and Carbon::setTestNow()) have any production implication for long-running workers?

Integration Approach

Stack fit

Native Laravel idiom throughout: a middleware, a config file, a cache store, a Blade view, an exception-handler-integrated reporter. Fits existing Horizon/supervisor deployments without new infrastructure. The only new runtime dependency is cache availability and headroom, which every Laravel app already has.

Migration path

There is no prior assessment and no prior install, so this is a greenfield adoption of v0.11.0 — but treat the release notes' "Upgrading" section as a checklist anyway, because it enumerates the failure modes we would otherwise rediscover ourselves:

  1. Pin ^0.11.0. Do not float across pre-1.0 minors.
  2. Enumerate every service key. Flag any containing a dot, and explicitly set threshold on each — do not rely on default_threshold.
  3. Decide peak windows deliberately, and set peak_hours_threshold where business-hours behavior is intended.
  4. If sharing a cache across apps, set a distinct fuse.cache.prefix per app from day one. Accept that history starts empty once.
  5. Audit for any custom recovery strategy that throws to stop a job; replace with an explicit skip/dead-letter mechanism.
  6. Republish --tag=fuse-views if we customize the status page, so the DATA UNAVAILABLE state is available.
  7. Keep $tries = 0 on Fuse-gated jobs, per the README.

Compatibility

Laravel/PHP version bounds are not stated in the notes — confirm before scoping. Behavioral compatibility is the real work: threshold resolution, listener exception propagation, gating-error handling, and status-page routing all changed. dispatchSync() and the sync driver diverge from the async path by design; CI must cover both. Existing uptime checks and dashboards pointing at /fuse and /fuse/data need their expected status codes updated (404 when disabled behind custom middleware; 503 during cache outage with the page itself still loading).

Sequencing

Adopt behind a single non-critical service first, with one dependency, in staging, and inject cache failures deliberately (flush the store, add latency, drop connections) to observe: job outcome preservation, release behavior, probe lock release, status page degradation, and recovery on the first good poll. Then roll out per service in ascending order of blast radius, with the payment-adjacent service last. Ship the runbook and the alert changes in the same change window as the config, not after.

Operational Impact

Maintenance

Small surface area (middleware + config + cache keys + one view), which keeps maintenance cheap, but pre-1.0 velocity means every minor deserves a read of the changelog. Realistically: one owner, ~1–2 hours per minor release to review and test, plus a config audit whenever threshold or naming semantics change. The Carbon unification is a genuine TCO win — the package's own suite went from 53 seconds to under one, and our integration tests can now advance the open timeout with travel() instead of sleep(), which removes flakiness and wall-clock cost from CI.

Support

Single-maintainer project. Bus factor is the primary support risk; mitigate by keeping our integration thin (middleware + config) so a fork or replacement is a contained exercise, and by tracking the upstream changelog rather than discovering changes at upgrade time. The quality of this changelog — every entry names the failure mode it fixes and the observable symptom — is a positive maturity signal and lowers the cost of that tracking.

Scaling

Every gated dispatch performs cache reads and writes; state churn scales with job volume, not with service count. On Redis this is negligible; on a database cache it becomes a hot table under high throughput and should be avoided. The status page polls independently of job volume. The genuine scaling concern is release storms: when a circuit is open or the cache is erroring, gated jobs release and re-enter, so queue depth and release churn become the load signal to watch, not error rate.

Failure modes

  • Cache unavailable: jobs preserve their real outcome; gating errors release rather than fail; /fuse/data returns 503 while the page still renders DATA UNAVAILABLE in red. Degrades correctly, but release churn rises.
  • Listener or reporter throws: reported, not propagated. A job can no longer be failed by its own transition listener.
  • Probe lock leak: fixed — a throwing CircuitBreakerOpened listener no longer holds the lock until TTL.
  • Stuck-open circuit: fixed for the case where the closing increment failed; recovery now completes on a successful probe.
  • Cross-app contamination via shared cache: fixed for status-page history and the kill switch; confirm circuit state namespacing separately.
  • Silent misconfiguration: dotted service names and missing thresholds no longer fall back silently.
  • Remaining blind spot: custom published views that were not republished will not show the outage state.

Ramp-up

Low for any Laravel developer — the concepts map onto middleware and config they already know. The subtle part is not the API but the semantics: a release counts as an attempt, thresholds interact with peak windows, listener exceptions are contained, and sync behaves differently from async. Budget a short internal write-up plus a staging chaos exercise, and put the $tries = 0 rule and the "release is an attempt" caveat in the runbook where on-call will find them.

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.
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle
glavweb/extra-bundle