Zizq — Official Ruby Client
This is the official Zizq client library for Ruby.
Zizq is a simple, zero dependency, single binary job queue system that is both fast and durable. It is designed to work in any stack through a simple HTTP API.
Features
- Multi-thread and/or multi-fiber concurrent worker (via
async) Zizq::Jobbased job classes, Active Job support, or completely custom- Enqueue and process jobs from one language to another
- Arbitrary named queues
- Granular job priorities
- Scheduled jobs
- Configurable backoff policies
- Configurable job retention policies
- Recurring jobs (cron)
- Job introspection and management APIs, with support for
jqquery filters - Unique jobs
Installation
[!NOTE] If you have not yet installed the Zizq server, follow the Getting Started guide first.
Add it to your application's Gemfile:
gem 'zizq', '~> 0.3.2'
Or install it manually:
$ gem install zizq -v 0.3.2
Ruby 3.2.8 or newer is required. Client and server share version numbers — keep the client's major/minor at or below the server's.
Configuration
Out of the box, the client talks to a server at http://localhost:7890 —
fine for local development. For anything else, configure it with
Zizq.configure in your application's bootstrap (e.g. a Rails initializer):
require 'zizq'
Zizq.configure do |c|
c.url = 'https://zizq.your.network:7890'
c.logger = Logger.new('log/zizq.log')
c.tls.ca = '/path/to/server-ca-cert.pem'
# Optional worker defaults — applied to every Zizq::Worker
# instance and to runs of the `zizq-worker` executable. Explicit
# kwargs or CLI flags override these.
c.worker.queues = ['emails', 'payments']
c.worker.fiber_count = 25
end
For mutual TLS, also set c.tls.client_cert and c.tls.client_key.
[!CAUTION] If your server is exposed directly to the internet, it should require mutual TLS — otherwise anybody can talk to it.
Usage
[!TIP] This README is an overview. The full documentation covers each feature in depth — middleware, custom dispatchers, Active Job, job querying, and more.
Defining a job
In most Ruby applications, a job is a plain class that includes Zizq::Job.
The class declares its defaults with the zizq_* DSL and implements
#perform:
class SendEmailJob
include Zizq::Job
zizq_queue 'emails'
zizq_priority 100
zizq_retry_limit 5
def perform(user_id, template:)
user = User.find(user_id)
Mailer.deliver(user, template)
end
end
Every default — zizq_queue, zizq_priority, zizq_retry_limit,
zizq_backoff, zizq_retention, zizq_unique — can be overridden per
enqueue. The job's class name ("SendEmailJob") becomes the API-level job
type, so keep it stable once jobs are in flight.
Enqueuing jobs
Enqueue a job by passing the class and the arguments your #perform method
expects:
job = Zizq.enqueue(SendEmailJob, 42, template: 'welcome')
job.id # => "03fu0wm75gxgmfyfplwvazhex"
Override defaults for a single call with Zizq.enqueue_with, or with a block
that mutates the request:
# Don't retry this one.
Zizq.enqueue_with(retry_limit: 0).enqueue(SendEmailJob, 42, template: 'welcome')
# Bump the priority via the block form.
Zizq.enqueue(SendEmailJob, 42, template: 'welcome') do |req|
req.priority = 1000
end
Schedule a job for later with delay (seconds from now) or an absolute
ready_at:
Zizq.enqueue_with(delay: 3600).enqueue(SendEmailJob, 42, template: 'welcome')
Zizq.enqueue_with(ready_at: Time.new(2027, 3, 15, 14, 30)).enqueue(SendEmailJob, 42, template: 'welcome')
To enqueue many jobs efficiently, Zizq.enqueue_bulk sends them in a single
atomic request — across queues and job types, and enqueue_raw enqueues can
be mixed in too:
Zizq.enqueue_bulk do |b|
signups.each { |user_id| b.enqueue(SendEmailJob, user_id, template: 'welcome') }
end
[!NOTE] Jobs can also be enqueued without
Zizq::JobviaZizq.enqueue_raw— designed for cross-language workflows where, for example, a Ruby app enqueues jobs consumed by a Go service.
Running a worker
Jobs are processed by a worker, typically in a separate process. The simplest
way is the zizq-worker executable bundled with the gem. Rails apps need
no arguments — zizq-worker auto-detects config/environment.rb when run
from the app's root:
$ bundle exec zizq-worker
I, [...] INFO -- : Zizq worker starting: 1 threads, 25 fibers, prefetch=50
I, [...] INFO -- : Connected. Listening for jobs.
For Sinatra or other apps, pass the entrypoint explicitly:
$ bundle exec zizq-worker app.rb
Worker defaults (queues, thread_count, fiber_count, prefetch) come
from your Zizq.configure { |c| c.worker.* } block. CLI flags
(--threads, --fibers, --queue, --all-queues, etc.) override the
configured defaults when needed. Leave --fibers 1 if your application
isn't fiber-safe — no Async context is loaded in that case. INT /
TERM trigger a graceful shutdown (drains in-flight jobs up to
--shutdown-deadline, default 30s).
For more control — for example running the worker in-process alongside a
Rack app — construct Zizq::Worker directly:
require 'zizq'
# Picks up queues, fiber_count, etc. from Zizq.configure { |c| c.worker.* };
# any kwarg here overrides those defaults.
worker = Zizq::Worker.new(queues: ['emails', 'payments'])
Signal.trap('INT') { worker.stop }
worker.run # blocks until the worker stops
#run blocks until the worker terminates; #stop drains in-flight jobs
gracefully, #kill forces an immediate stop. On any unclean shutdown the
server returns unfinished jobs to the queue — no job is lost.
Recurring jobs (cron)
Define a cron schedule in your application's startup code. Definitions are idempotent — every process can safely define the same schedule, and Zizq keeps the server in sync by adding, replacing, and removing entries as the definition changes. Cron requires a Pro license on the server.
Zizq.define_crontab('maintenance', timezone: 'Europe/London') do |cron|
# Every 15 minutes.
cron.define_entry('refresh_warehouse', '*/15 * * * *').enqueue(
RefreshWarehouseJob, incremental: true
)
# 9am London time, every day.
cron.define_entry('daily_digest', '0 9 * * *').enqueue(SendDailyDigestJob)
end
Once defined, schedules can be inspected and managed via
Zizq.crontab('maintenance') — paused/resumed at the schedule level or per
entry, and deleted entirely when no longer needed.
Resources
Support & Feedback
If you need help using Zizq, create an issue on the zizq-ruby repo. Feedback is very welcome.
License
MIT — see LICENSE.