ivan1986/supervisor
ivan1986/supervisor is a Laravel package for managing Supervisor process configuration and control. It helps define and generate worker programs for queues and background jobs, simplifying deployment and keeping supervised processes organized.
Reality check first: despite the ivan1986/supervisor name, this is SupervisorBundle — a Symfony bundle, not a Laravel package. It ships a service wrapper around supervisord's XML-RPC interface plus console commands and a small admin UI. There are 8 stars, 0 dependents, and a 0.1 score, so treat it as a reference implementation you may vendor rather than a dependency you composer require and forget.
Minimal path for a Laravel developer:
supervisord.conf needs either:
[unix_http_server]
file=/var/run/supervisor.sock
chmod=0700
[rpcinterface:supervisor]
supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface
or an [inet_http_server] block on 127.0.0.1:9001. Without this, nothing works — the default supervisorctl-only setup exposes no socket the bundle can reach.DependencyInjection/Configuration.php (the exact config keys — host/port vs. socket path) and the Supervisor service class (the actual method surface: getAllProcessInfo, startProcess, stopProcess, restartProcess, etc. — thin wrappers over supervisord's RPC method names). The Command/ directory shows the intended usage patterns.fxmlrpc client pointed at your socket/HTTP endpoint, and bind it as a singleton in a service provider. Symfony's DI compiler passes will not run under Laravel's container and you'll waste a day fighting autoconfiguration.First use case: a php artisan supervisor:status command that calls getAllProcessInfo() and prints name, state (RUNNING/FATAL/BACKOFF), PID, and uptime — immediately useful for spotting dead queue workers after a deploy.
Bind it as a singleton, don't resolve it per call. Each XML-RPC client holds a socket handle; building one per request is wasteful and can exhaust file descriptors on high-traffic workers.
// app/Providers/SupervisorServiceProvider.php
public function register(): void
{
$this->app->singleton(SupervisorClient::class, function () {
return new SupervisorClient(
config('supervisor.socket', 'unix:///var/run/supervisor.sock'),
timeout: 5,
);
});
}
Wrap the RPC calls in your own thin adapter. Do not let the bundle's class leak into controllers. Supervisord's RPC has return shapes ({name, group, state, statename, pid, ...}) that you'll want normalized into value objects or arrays your app controls. This also makes it trivial to swap the transport later.
Artisan commands are the natural home. A small command set — supervisor:status, supervisor:restart {program}, supervisor:tail {program} — covers 90% of day-to-day need and gives you a stable interface even if the underlying library changes.
foreach ($client->getAllProcessInfo() as $p) {
if (in_array($p['statename'], ['FATAL', 'BACKOFF'], true)) {
$client->startProcess($p['name'], $p['group']);
}
}
Health check integration. Expose /health (or a scheduled Schedule::command('supervisor:status')) that fails if any program is FATAL or STOPPED unexpectedly. This catches the classic failure where a worker dies at 3am and nothing notices until the queue backs up.
Deploy hook. After artisan migrate, restart workers via RPC (stopProcessGroup then startProcessGroup) rather than shelling out to supervisorctl. The RPC path gives you structured errors and doesn't require the deploy user to be in the supervisor group. If the RPC route is blocked, supervisorctl restart 'queue-worker:*' is the pragmatic fallback.
Iterate, don't assume a single program. Programs declared with numprocs=N appear as name_00, name_01, … Always list-and-match by prefix (str_starts_with($p['name'], 'queue')) rather than hardcoding one name.
symfony/dependency-injection, symfony/http-kernel, and symfony/config. Composer will install them, but the bundle will never register itself in Laravel. Plan to use only the underlying RPC wrapper class, or skip the package and call XML-RPC with fxmlrpc/curl directly — the API surface is small enough that reimplementation is often less work than adaptation./var/run/supervisor.sock (commonly 0700 owned by root). Symptoms are a connection refused or permission denied that looks like a network problem. Fix with chmod=0770 plus a shared group, not by switching FPM to root.restartProcess exists in newer RPC interfaces but wraps stop+start. For groups, do stopProcessGroup → poll until STOPPED → startProcessGroup, or you'll race and get "already started" errors.(name, group); passing null group only works for the default group. Copy the exact group from getAllProcessInfo().stopwaitsecs). Always set an explicit client timeout (5–10s) and catch transport exceptions — an uncaught timeout in a health check will take down your monitoring path.app/Supervisor/ and own it.supervisorctl status (proves the daemon side is healthy) → tail -f /var/log/supervisor/supervisord.log → raw RPC (curl -u user:pass http://127.0.0.1:9001/RPC2 -d '...' if the inet server is on) → your wrapper. If step 1 works and step 4 doesn't, it's a permissions or endpoint-config problem, not a code problem.supervisorctl invoked via Process is the better answer for everything else. Use this package only if you specifically want in-process RPC control from PHP.How can I help you explore Laravel packages today?