zeridion-flare (Ruby)
Ruby SDK for the Zeridion Flare managed background-jobs API.
Full documentation at docs.zeridion.com/flare
Installation
gem install zeridion-flare
Or add to your Gemfile:
gem "zeridion-flare", "~> 0.2"
Requires Ruby 3.2+. Zero runtime dependencies — uses stdlib Net::HTTP, OpenSSL, and JSON only. The opt-in worker runtime (require "zeridion_flare/worker") ships in the same gem and adds no dependencies.
Quick start
require "zeridion_flare"
client = Zeridion::Flare::Client.new(api_key: "zf_live_sk_...")
# Or, with FLARE_API_KEY set in the environment:
# client = Zeridion::Flare::Client.new
job = client.create_job(
"job_type" => "SendWelcomeEmail",
"payload" => { "email" => "alice@example.com" },
"queue" => "default",
)
puts job["id"], job["state"] # "job_abc123", "pending"
Client.new(...)
| Keyword | Default | Notes |
|---|---|---|
api_key: |
ENV["FLARE_API_KEY"] |
Required — pass directly or via env var |
base_url: |
https://api.zeridion.com |
Override for dev / staging environments |
max_retries: |
3 |
Set 0 to disable retries |
retry_base_delay_ms: |
500 |
Base for exponential schedule |
retry_max_delay_ms: |
30_000 |
Cap on a single backoff wait (and on Retry-After) |
timeout_seconds: |
30 |
Per-request read timeout |
transport: |
NetHttpTransport.new |
Swap for tests or to plug in a logging proxy |
Every public method accepts optional idempotency_key: and request_id: keyword arguments, sent as the Idempotency-Key and X-Request-Id headers.
client.create_job(body, idempotency_key: "optional", request_id: "optional")
client.get_job(id) # nil if 404
client.list_jobs(state: "failed", limit: 25)
client.cancel_job(id) # nil if 409
client.retry_job(id) # nil if 409
client.register_worker(body) # raises on non-2xx
client.poll_workers(body)
client.heartbeat(body) # {"status" => "ok" | "cancel"}
client.ack_worker(body)
Automatic retries
The SDK auto-retries HTTP 429 / 502 / 503 / 504 responses and transient network errors with full-jitter exponential backoff capped at retry_max_delay_ms. The Retry-After header is honored when present.
See the stable error-code registry for every error.code string the API can return.
Error handling
All API errors inherit from Zeridion::Flare::FlareError:
begin
client.create_job("job_type" => "MyJob")
rescue Zeridion::Flare::RateLimitError => e
sleep(e.retry_after.to_i) # honor X-RateLimit-Reset
rescue Zeridion::Flare::AuthError
# 401 — invalid API key
rescue Zeridion::Flare::ConflictError => e
case e.code
when "idempotency_key_reuse"
# Same Idempotency-Key reused with a different body
end
rescue Zeridion::Flare::FlareError => e
warn "Error #{e.status_code}: #{e.code} — #{e.} (req #{e.request_id})"
end
Each error exposes #status_code, #code, #request_id, and #message. RateLimitError additionally exposes #limit, #remaining, #retry_after.
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:
require "zeridion_flare"
post "/hooks/zeridion" do
payload = request.body.read
header = request.env["HTTP_X_ZERIDION_SIGNATURE"].to_s
unless Zeridion::Flare::Webhook.verify(payload, header, ENV["ZERIDION_WEBHOOK_SECRET"], tolerance_seconds: 300)
halt 400, "invalid signature"
end
# ... process the event ...
200
end
Webhook.verify is HMAC-SHA256 over <unix_timestamp>.<raw_body>, constant-time-compared (via OpenSSL.secure_compare) against every v1= value in the header (supports secret rotation). The optional tolerance_seconds: parameter rejects replays older than that many seconds.
Worker runtime
Beyond the thin client, the gem ships an opt-in background-worker runtime. Define job classes and let it register, long-poll, dispatch, heartbeat with progress, honor server cancellation, and drain gracefully on shutdown — instead of hand-writing the poll/ack loop.
require "zeridion_flare/worker"
class SendWelcomeEmail
include Zeridion::Flare::Job
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
# Recurring (cron) jobs are payloadless and run on a schedule:
class NightlyCleanup
include Zeridion::Flare::RecurringJob
cron: "0 3 * * *", queue: "maintenance", timezone: "UTC"
def perform(ctx)
PurgeExpired.run
end
end
worker = Zeridion::Flare::Worker::Worker.new(concurrency: 5)
worker.run # blocks; SIGTERM/SIGINT → graceful drain
Including the Job / RecurringJob mixin registers the class automatically.
The worker reads the same FLARE_API_KEY fallback and base-URL default as the
thin client. Handlers run at least once — dedupe on ctx.job_id to stay
idempotent.
Full reference: docs.zeridion.com/flare/sdks/ruby/worker.
Sample app
A runnable worker starter (one payload job + one recurring job + graceful drain,
plus an enqueue.rb feeder) lives at
samples/ruby-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
- PHP SDK: ../php/README.md