Ruby worker runtime
The zeridion-flare gem ships an opt-in worker runtime alongside the thin
client. Instead of hand-writing a poll/ack loop, you define job classes and let
the worker register, long-poll for work, dispatch each job to your handler,
heartbeat with progress, honor server-side cancellation, and drain gracefully
on shutdown.
The runtime lives behind a separate require so thin-client programs stay lean:
require "zeridion_flare/worker"
Requires Ruby 3.2+.
Quick start
require "zeridion_flare/worker"
class SendWelcomeEmail
include Zeridion::Flare::Job
flare_options queue: "email", max_attempts: 5, timeout: 120
def perform(payload, ctx)
return if ctx.cancelled?
return if AlreadySent.exists?(ctx.job_id) # at-least-once → idempotent
Mailer.welcome(payload["email"]).deliver_now
ctx.report_progress(1.0)
end
end
worker = Zeridion::Flare::Worker::Worker.new(concurrency: 5)
worker.run # blocks; SIGTERM/SIGINT → graceful drain
Set FLARE_API_KEY in the environment (or pass api_key: to
Worker.new). The worker reads the same FLARE_API_KEY fallback and base-URL
default as the thin client.
What the runtime does for you
On start/run, the worker:
- Builds a stable worker identity and announces itself — the queues it serves, the job types it can run, and any recurring schedules. Announcement is best-effort: if it fails, the worker logs it and keeps going.
- Long-polls for work, asking only for as many jobs as it has free slots.
- Dispatches each job to your
#perform, on a bounded thread pool. - Heartbeats each in-flight job on a fixed cadence, carrying the latest reported progress, and watches the response for a cancellation signal.
- Acknowledges the outcome —
succeededorfailed. The server decides whether a failed job retries or is parked; the worker only reports. - On
SIGTERM/SIGINT, stops claiming new work and drains in-flight jobs before exiting.
Lifecycle
| Method | Behaviour |
|---|---|
#start | Spawn the poll loop on a background thread and return immediately. Idempotent. |
#run | #start, install SIGTERM/SIGINT handlers, then block until a signal arrives, then drain. Use this for a standalone worker process. |
#stop | Idempotent. Stop polling and drain in-flight jobs within the shutdown grace, then return. |
Signals are only installed inside #run. If you embed the worker in a larger
process, call #start and wire your own shutdown to #stop.
Concurrency & backpressure
concurrency: (default 10) caps how many jobs run at once. The worker only
ever asks the server for as many jobs as it has free slots, so it never pulls
more than it can run. Because Ruby releases the global lock on I/O, an
I/O-bound workload gets real parallelism; for CPU-bound work, prefer a lower
concurrency and run more worker processes.
At-least-once delivery — make handlers idempotent
Acknowledgement is best-effort. If a worker finishes a job but crashes before
the ack lands, the server re-delivers the same job to another worker. Your
handler therefore runs at least once, occasionally more — so it must be
idempotent. Dedupe on ctx.job_id (a unique row, a SETNX, an outbox record).
This is the one load-bearing contract of the worker model.