zeridion / flare
Official PHP SDK for the Zeridion Flare managed background-jobs API
Package info
pkg:composer/zeridion/flare
Requires
- php: >=8.2
- ext-curl: *
- ext-json: *
Requires (Dev)
- phpunit/phpunit: ^10.5
Suggests
- ext-pcntl: Enables background heartbeats and graceful (SIGTERM) shutdown in the worker runtime. Without it the worker still runs in a degraded mode (coarse liveness, no preemptive cancel).
- ext-posix: Used alongside ext-pcntl for worker process control.
README
PHP SDK for the Zeridion Flare managed background-jobs API.
Full documentation at docs.zeridion.com/flare
Installation
composer require zeridion/flare-php
Requires PHP 8.2+, ext-curl, and ext-json. Zero third-party dependencies — uses curl directly, no Guzzle / Symfony HTTP coupling.
Quick start
use Zeridion\Flare\FlareClient; $client = new FlareClient(apiKey: 'zf_live_sk_...'); // Or, with FLARE_API_KEY set in the environment: // $client = new FlareClient(); $job = $client->createJob([ 'job_type' => 'SendWelcomeEmail', 'payload' => ['email' => 'alice@example.com'], 'queue' => 'default', ]); echo $job['id'], ' ', $job['state']; // "job_abc123 pending"
new FlareClient(...)
| Argument | Type | Default | Notes |
|---|---|---|---|
apiKey |
?string |
getenv('FLARE_API_KEY') |
Required — pass directly or via env var |
baseUrl |
string |
https://api.zeridion.com |
Override for dev / staging environments |
maxRetries |
int |
3 |
Set 0 to disable retries |
retryBaseDelayMs |
int |
500 |
Base for exponential schedule (ms) |
retryMaxDelayMs |
int |
30000 |
Cap on any single backoff wait |
timeoutSeconds |
float |
30.0 |
Per-request curl timeout |
transport |
?HttpTransport |
new CurlTransport() |
Swap in for tests or to plug in a logging proxy |
Methods
Every public method accepts optional idempotencyKey and requestId parameters, sent as the Idempotency-Key and X-Request-Id headers respectively.
$client->createJob($body, idempotencyKey: 'optional', requestId: 'optional'); $client->getJob($id); // returns null if 404 $client->listJobs(state: 'failed', limit: 25); $client->cancelJob($id); // returns null if 409 $client->retryJob($id); // returns null if 409 $client->registerWorker($body); // worker-side $client->pollWorkers($body); // worker-side $client->heartbeat($body); // worker-side $client->ackWorker($body); // worker-side
Most apps will use the built-in worker runtime rather than calling the low-level worker methods directly.
Automatic retries
The SDK auto-retries HTTP 429 / 502 / 503 / 504 responses and transient network errors (curl errors caught from CurlTransport) with full-jitter exponential backoff capped at retryMaxDelayMs. The Retry-After response header is honored when present (integer seconds).
See the stable error-code registry for every error.code string the API can return.
Error handling
All API errors extend FlareException. Typed subclasses let you discriminate:
use Zeridion\Flare\{FlareClient, FlareException, AuthException, RateLimitException, ConflictException}; try { $client->createJob(['job_type' => 'MyJob']); } catch (RateLimitException $e) { sleep($e->retryAfter ?? 1); // honor X-RateLimit-Reset (epoch) } catch (AuthException $e) { // 401 — invalid API key } catch (ConflictException $e) { if ($e->errorCode === 'idempotency_key_reuse') { // Same Idempotency-Key reused with a different body } } catch (FlareException $e) { echo "Error {$e->statusCode}: {$e->errorCode} — {$e->getMessage()} (req {$e->requestId})"; }
Each FlareException exposes $statusCode, $errorCode, $requestId and the parent \Exception::getMessage(). (Property is named errorCode not code because PHP's \Exception already declares a non-readonly $code that a readonly string can't redeclare.)
Verifying webhook signatures
If you've configured outbound webhooks via the /flare/v1/webhooks API, verify the X-Zeridion-Signature header on each incoming delivery:
use Zeridion\Flare\Webhook; $body = file_get_contents('php://input'); $header = $_SERVER['HTTP_X_ZERIDION_SIGNATURE'] ?? ''; if (!Webhook::verify($body, $header, $secret, toleranceSeconds: 300)) { http_response_code(400); exit('invalid signature'); } // ... process the event ...
Webhook::verify is HMAC-SHA256 over <unix_timestamp>.<raw_body>, constant-time-compared (via hash_equals) against every v1= value in the header (supports secret rotation). The optional toleranceSeconds parameter rejects replays older than that.
Background worker
The package ships a built-in worker under the Zeridion\Flare\Worker
namespace. Define your jobs as classes decorated with #[FlareJob], register
them, and the worker registers itself, long-polls for work, dispatches each job
to its handler, heartbeats with progress, honours server cancellation, and
drains the in-flight job on SIGTERM / SIGINT.
use Zeridion\Flare\Worker\{FlareJob, FlareWorker, Job, JobContext, RecurringJob, WorkerOptions}; #[FlareJob(queue: 'email', maxAttempts: 5, timeoutSeconds: 60)] final class SendWelcomeEmail implements Job { public function handle(mixed $payload, JobContext $ctx): void { if ($this->alreadySent($ctx->jobId)) return; // at-least-once → idempotent $this->mailer->send($payload['email']); $ctx->reportProgress(1.0); } } #[FlareJob(cron: '0 3 * * *', queue: 'maintenance', timezone: 'UTC')] final class NightlyCleanup implements RecurringJob { public function handle(JobContext $ctx): void { $this->purgeExpired(); } } $worker = new FlareWorker(WorkerOptions::fromEnv()); $worker->register(SendWelcomeEmail::class); $worker->register(NightlyCleanup::class); exit($worker->run());
Notes:
- One job per process. Stock PHP has no shared-memory threads, so the worker runs one job at a time. Scale out with multiple processes under a supervisor.
- Optional
ext-pcntl/ext-posixenable background heartbeats and gracefulSIGTERMshutdown. Without them the worker still runs, with coarser liveness and no preemptive cancellation. - Cooperative cancellation. Long-running handlers should poll
$ctx->cancellationRequested()and unwind on their own. - At-least-once delivery. Make handlers idempotent (guard on
$ctx->jobId).
A ready-to-run worker also ships via the bin/flare-work command (discovers
#[FlareJob] classes and runs the worker from environment configuration).
Full guide: docs.zeridion.com/flare/sdks/php/worker.
Sample app
A runnable worker starter (a payload job, a recurring job, progress, and
graceful drain, plus a feeder) lives at
samples/php-starter/.
Links
- Documentation: https://docs.zeridion.com/flare
- Dashboard: https://dashboard.zeridion.com/
- .NET SDK: ../csharp/README.md
- TypeScript SDK: ../typescript/README.md
- Python SDK: ../python/README.md
- Go SDK: ../go/README.md