PHP worker
The zeridion/flare package ships a built-in worker under the
Zeridion\Flare\Worker namespace. Define your jobs as classes, register them,
and the worker announces itself, long-polls for work, dispatches each job to
its handler, heartbeats with progress, honours server-side cancellation, and
drains the in-flight job on shutdown.
The worker is opt-in — importing it does not change the thin client, so a project that only enqueues jobs stays lean.
Install
composer require zeridion/flare
For background heartbeats and graceful SIGTERM shutdown, also enable the
optional ext-pcntl and ext-posix extensions. Without them the worker still
runs, with coarser liveness and no preemptive cancellation (see
Cancellation & timeouts).
One job per process
Stock PHP has no shared-memory threads, so the worker runs one job per
process. Scale throughput by running multiple worker processes under a
process supervisor — see Running a fleet. A concurrency
greater than 1 is accepted but has no effect on a single process and logs a
warning at startup.
Quick start
<?php
require __DIR__ . '/vendor/autoload.php';
use Zeridion\Flare\Worker\FlareWorker;
use Zeridion\Flare\Worker\WorkerOptions;
$worker = new FlareWorker(WorkerOptions::fromEnv());
$worker->register(SendWelcomeEmail::class);
$worker->register(NightlyCleanup::class);
exit($worker->run());
run() blocks until the process receives SIGTERM / SIGINT, then finishes
the in-flight job and returns an exit code (0 = clean shutdown).
Define SendWelcomeEmail and NightlyCleanup with the
#[FlareJob] attribute — see Defining a payload
job and Recurring jobs.
What the worker does
On run() the worker:
- Builds a stable worker id of the form
wrk_{host}_{pid}_{random}(the host is sanitised and a cryptographically-random suffix is appended so two workers never collide). - Announces its served queues, job types, and any recurring schedules. Registration is best-effort — a failure is logged and the worker keeps polling.
- Long-polls for jobs, requesting only as much work as it has free capacity for.
- For each job: emits one heartbeat immediately, dispatches to your handler
with a
JobContext, heartbeats on a cadence while the job runs, and acknowledges the outcome. - On shutdown, stops polling, finishes the job in flight, and exits.
Heartbeats & progress
While a job runs the worker sends periodic heartbeats so the server knows the
job is alive. Each heartbeat carries the latest progress you've reported via
$ctx->reportProgress(). The cadence is
max(10s, timeout / 3).
If the server replies to a heartbeat asking the job to cancel, the worker trips the job's cancellation handle (see below) and acknowledges the job as failed.
Cancellation & timeouts
Cancellation in PHP is cooperative. A handler must check
$ctx->cancellationRequested() (or call
$ctx->throwIfCancelled()) at safe points and unwind on its own. A handler
that never yields cannot be interrupted from the outside and is bounded only by
the server reclaiming the job after it goes silent.
A job is cancelled when any of these happen:
- its configured timeout elapses,
- the server asks for cancellation in a heartbeat response, or
- the worker is shutting down.
Because acknowledgements are best-effort, jobs run at-least-once — if an
ack is lost after the work completes, the same job is delivered again. Make
handlers idempotent: guard externally-visible side effects on
$ctx->jobId.
Graceful shutdown
On SIGTERM / SIGINT the worker stops accepting new work and finishes the
job it is currently running before exiting — no job is abandoned. Give the
process enough time to drain (match your supervisor's stop-wait to your longest
job timeout) before it is force-killed.
Running a fleet
Run several worker processes to handle jobs concurrently. With a process
supervisor, set the process count to your desired concurrency and forward
SIGTERM for graceful shutdown. The starter sample ships a ready-to-adapt
supervisor configuration.
Configuration
The worker reads FLARE_API_KEY, FLARE_BASE_URL, FLARE_QUEUES, and
FLARE_POLL_INTERVAL from the environment, with everything else defaulted. See
Worker options and Configuration precedence.