medicorenl/daemon-bundle
Daemon Bundle is a PHP package for building and managing long-running daemon processes. It offers a base daemon class, signal handling, PID file management, graceful shutdown, and logging to keep background workers reliable and easy to operate.
medicorenl/daemon-bundle is a Symfony2 bundle, not a Laravel package. There is no service provider, no config/daemon.php, and no auto-discovery — so a Laravel developer cannot composer require it into an app/ and expect anything to happen. Treat this section as "what you'd do if you were in a Symfony2 codebase," because that is the only context in which the package has any meaning.
Minimal setup in its native environment:
composer require medicorenl/daemon-bundle (PHP 5.x-era constraint likely; expect it to fight with modern PHP).app/AppKernel.php:
$bundles = array(
// ...
new MedicoreNL\DaemonBundle\DaemonBundle(),
);
Command/ directory first — that is where the daemon base class and any provided daemon:* commands will live. Read the base class constructor and configure() method before anything else; the available options (pid file, log file, user/group, detach, umask) are the entire public API.DependencyInjection/ for the service id and any parameters (pid path, log path) you can override in app/config/config.yml.If you are genuinely on Laravel: skip the package. Use supervisor + an artisan command, or laravel/horizon for queues. The concept (detach, pid file, signal handling, logging) is worth borrowing; the code is not.
Inherit the daemon base command. The usual shape of a bundle like this is a DaemonCommand (or AbstractDaemonCommand) that you extend. You typically implement a single execute()/run() loop and let the base class handle daemonization:
class ConsumeEventsCommand extends DaemonCommand
{
protected function configure()
{
parent::configure(); // keep pid/log/detach options
$this->setName('app:consume-events');
}
protected function execute(InputInterface $input, OutputInterface $output)
{
while (true) {
$this->processOneBatch();
$this->checkForStopSignal(); // or rely on base class
usleep(250000);
}
}
}
Drive it from the CLI, not from HTTP. The intended workflow is:
php app/console app:consume-events --detach --pid-file=/var/run/consume.pid
php app/console app:consume-events --stop --pid-file=/var/run/consume.pid
Verify the exact option names against configure(); they vary across bundles of this vintage.
Use your DI container inside the loop. Because the command runs under the kernel, you can $this->getContainer()->get('doctrine') etc. But be careful: on Symfony2 the container is not reset between iterations, so a leaked entity manager is a real problem (see Gotchas).
Pair with a process supervisor anyway. Even when the bundle forks, most teams still wrap it in supervisor or systemd so it restarts after crashes and on deploy. The bundle's pid file then becomes a debugging artifact, not the source of truth.
Log to file, not stdout. Once detached, stdout is gone. Route the loop's output through the bundle's logger option or through Monolog configured for a file handler with rotation.
Integration tip for other commands. Expose a small admin command (app:daemon:status) that reads the pid file and checks posix_kill($pid, 0) so operators can see whether the worker is actually alive.
each(), create_function(), dynamic properties, etc.AppKernel.php. If the bundle is installed but commands don't appear in php app/console list, the registration step is the first thing to check.pcntl_fork, posix_setsid, and friends. These are disabled in many shared hosts and some Docker base images. Check php -m before anything else; a missing pcntl usually manifests as a silent no-op or a vague fatal, not a clean error.SIGTERM/SIGINT to be handled but not SIGHUP reload. Test graceful shutdown explicitly; a pid-file-only implementation will orphan workers if the parent dies.posix_kill($pid, 0) plus verifying /proc/$pid/cmdline contains your command name — otherwise you may signal an unrelated PID that got recycled.--no-detach or omit --detach) with -vvv. Add error_log() or a file logger at the top of the loop; once daemonized, you lose terminal output entirely.$em->clear() periodically, and cap iteration counts so the supervisor recycles the process (e.g. exit after 10k jobs).supervisor + a first-class Laravel command, horizon, or spatie/laravel-schedule-monitor. If you must study daemonization patterns in PHP, read systemd/supervisord docs and symfony/process; this bundle is not a good reference and won't run in your stack.How can I help you explore Laravel packages today?