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

Daemon Bundle Laravel Package

m6web/daemon-bundle

Symfony bundle for turning console commands into long-running daemons. Extend the provided daemon command, implement your loop, and get signal handling, graceful shutdown, and simple process lifecycle management without boilerplate. Ideal for workers, queue consumers, and background jobs.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

Architecture fit — unchanged at the layer, marginally better at the seam. m6web/daemon-bundle (now BedrockStreaming/DaemonBundle) remains a Symfony bundle: Bundle subclass, registerBundles(), container extension, config tree. None of that exists in Laravel, so DaemonBundle::boot() stays inert and the transferable surface remains the abstract daemonized-command base class on Symfony\Component\Console\Command\Command. What v9.0.0 changes is the composition of that surface: signal handling has moved out of a method override and into a ConsoleCommandListener registered against the Symfony Console event dispatcher. That is a meaningful shift in our favour — a listener is a portable concept that Laravel's Artisan can dispatch, whereas an overridden handleSignal() was reachable only by inheritance. Re-estimate transferable value at roughly 30–40%, up from 20–30%, still on the fork-and-adapt path.

Integration feasibility — medium-low, now with a narrower fork. Path (a) (vendor the base class into app/Console/Daemons/) and path (b) (internal package with ServiceProvider + Artisan::starting()) both stand, but the listener refactor moves roughly the same code out of the class and into a registration hook. For us, that is a net simplification: our internal abstraction can compose a listener via Artisan::starting() rather than requiring every daemon to extend a bespoke base class. Both paths remain multi-sprint for a senior engineer because the loop, drain semantics, and container lifecycle are still ours to own — the release did not add any Laravel-facing integration.

Technical risk.

  • Breaking change in v9.0.0: handleSignal is removed from the bundle in favour of ConsoleCommandListener. Any fork or vendored copy that overrode handleSignal breaks on upgrade. Critically, Symfony 7.3 introduces its own handleSignal on the command layer, so a stale vendored override can now produce a signature-compatibility fatal, not just a silent behaviour change. Our spike branch must be audited for this before any Symfony bump.
  • Symfony version surface widened, not narrowed: the release is explicitly a Symfony 7.3 compatibility fix, which means upstream now tracks a newer Symfony floor. That is directionally good for Laravel 11/12 (which pin Symfony Console 6.4/7.x) but it is an inference — the actual composer.json constraints must be read, not assumed. A package requiring ^7.3 will not install on a Laravel 11 app locked to Symfony 7.0–7.2.
  • Extension dependency: pcntl and ext-posix remain hard requirements. Still unavailable on Windows, often absent from minimal php:cli images. Verify across the fleet before design work.
  • Long-lived process hazards (unchanged): Eloquent connection state, DB::reconnect(), scoped bindings never resetting, unbounded memory from models and query logs, and no built-in --max-time/--memory guardrails analogous to queue:work.
  • Abstraction overlap (unchanged): Laravel already ships daemon-mode primitives — queue:work, Horizon, schedule:run under cron, Octane for HTTP. The risk of introducing a second, non-idiomatic concurrency model is not reduced by this release.
  • New risk introduced by the listener model: signal-listener registration is now a runtime wiring concern rather than an inheritance concern. If the listener is registered on the wrong dispatcher (or double-registered), SIGTERM handling fails open — the process dies mid-iteration instead of draining. That failure is invisible until a deploy.

Key questions for the team.

  1. What is the actual workload — polling an API, consuming a stream/socket, aggregating data? If it is queue consumption, the answer remains Horizon, not this.
  2. What does v9.0.0 declare for symfony/console / symfony/http-kernel constraints, and does that intersect our composer.lock on Laravel 11 and 12?
  3. Does the ConsoleCommandListener register against the Symfony Console event dispatcher only, or is there bundle-side glue that would need re-implementation for an Artisan::starting() hook?
  4. Do our production and staging images have pcntl/posix enabled, and is Windows or ephemeral-dyno hosting in scope?
  5. Who owns the fork, and does our fork track upstream tags or pin a commit? A major-version release driven by an upstream framework conflict is exactly the event that strands an unowned fork.
  6. Does the listener drain in-flight work on SIGTERM, or exit mid-iteration?
  7. What coordinates duplicate work across N supervisors — Cache::lock, Redis, or nothing?

Integration Approach

Stack fit. Laravel and this package still intersect only at symfony/console. v9.0.0 makes that intersection slightly richer — console event listeners are a supported extension point — but the kernel, container, DI extension, and config tree remain foreign. Treat the package as a reference implementation, now with a clearer architectural cue: model our internal AbstractDaemonCommand around a listener-driven signal trap rather than a method override, since that is both upstream's direction and the pattern that survives Symfony minor bumps.

Migration path. Sequenced:

  1. Constraint check (half a day): resolve upstream v9.0.0 composer.json against our app locks. If the Symfony floor exceeds our pin, the evaluation ends here.
  2. Spike (1 week): vendor the base class and the listener into a throwaway branch. Run one low-risk command under supervisord; measure RSS over 24h; confirm SIGTERM drain and that no handleSignal override collides with Symfony 7.3.
  3. Harden: add --max-iterations, --memory-limit, DB::reconnect(), per-work-item Cache::lock(), structured logging, liveness heartbeat, and explicit listener-registration idempotency.
  4. Package internally: wrap in app/Console/Daemons (or a private composer package) with a ServiceProvider, an Artisan::starting() hook, and a publishable supervisor unit template.
  5. Generalize: only after two or three commands succeed should this become a team convention.

Compatibility. PHP 8.1+, Unix only, CLI SAPI only. Must not run under FPM/CGI. Symfony 7.3 is now the reference target for signal handling — verify our Laravel versions can meet it, and note that Laravel Octane is a different process model and must not be conflated with this.

Sequencing recommendation. Still: do not composer require this into a long-lived application. Fork-and-adapt remains lower-risk and lower-TCO, and v9.0.0 slightly improves the payoff of that fork because the listener is easier to re-host than an inherited method. But the release also proves the fork must be maintained against a moving Symfony target — budget for that explicitly.

Operational Impact

Maintenance. Signal on the project is mixed but net-neutral-to-slightly-positive: v9.0.0 is a real compatibility fix landed promptly against a Symfony 7.3 conflict, and it came from a contributor outside the original vendor (@pforesi), which is a modest improvement on bus factor. It is still one PR against a repo with ~59 stars and no dependents, and the release is a major version bump — upstream is willing to break its API to track Symfony, which is correct engineering but means our fork inherits a moving target. Keep a named owner and a quarterly review; add a specific trigger to that review: any Symfony Console release that touches signal handling.

Support. Unchanged. No Laravel-community channel, no Laravel-oriented docs, no Stack Overflow corpus. Debugging falls back to Symfony bundle source plus, now, Symfony Console's own signal-handling internals. Internal runbook must be extended with one new item: how to confirm the console listener is registered and firing (a startup log line at registration, plus a heartbeat).

Scaling. Unchanged. One process per daemon; no distribution or leader election. Horizontal scale means N supervisors with Cache::lock()/Redis coordination and idempotent handlers. Memory growth remains the primary ceiling — plan supervisord with stopwaitsecs, autorestart, and a max-memory restart trigger.

Failure modes to instrument for.

  • Silent stall: loop alive, no work processed, no error logged. Mitigation: heartbeat metric + staleness alert.
  • Listener not registered / double-registered: new in v9.0.0. Symptom is a process that ignores SIGTERM and is SIGKILLed on deploy, or a handler that fires twice. Mitigation: assert single registration at boot and log it.
  • Zombie/orphan processes after deploy: mitigation: SIGTERM-first restart policy with drain timeout.
  • Supervisor restart loop masking a crash: alert on restart rate, not just process count.
  • Partial state from SIGKILL: mitigation: idempotent work units and transactional writes.
  • DB connection drop after idle: mitigation: DB::reconnect() at loop top with backoff.
  • Log flooding from tight loops: mitigation: rate-limited logging and a minimum sleep interval.

Ramp-up. Non-trivial and essentially unchanged. Engineers need Unix signals, event-loop semantics, long-lived PHP memory behaviour, and the Laravel container's lifecycle across iterations. v9.0.0 adds a small amount of required literacy — Symfony Console's event dispatcher and where Laravel's Artisan exposes it — but does not move the estimate: one to two sprints for a senior engineer to reach production confidence on the first command, plus a sprint to make it a repeatable pattern.

TPM recommendation. Low strategic value in its current form. v9.0.0 is a credible, timely compatibility fix that modestly improves the case for a fork and does nothing for the case for a dependency. Approve a one-week spike only if the workload genuinely does not fit queue:work, Horizon, or schedule:run — and gate that spike on question 2 (Symfony constraint intersection) being answered first, because a version conflict there closes the investigation for free. Expected outcome remains a small internal abstraction inspired by this package.

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.
gmostafa/php-graphql-client
xeviant/paystack
snowsoft/faker
meditationsteps/blogetc
animalyoung/laravel-influxdb
onix-solutions/sms-telera
lonely-lights/prosetta
oxygen/data
oxygen/core
jengo/base
xiloryx/log-collector
a21ns1g4ts/filament-stripe
la-php/laravel-admin
artisan-build/community-prompts
vleroy/smart
ayles-software/laravel-australian-public-holidays
cboxdk/laravel-id-spatie
cboxdk/laravel-id-billing
cboxdk/laravel-id-billing-bridge
simple-as-fuck/php-performance-log