que-rb/que
A Ruby job queue that uses PostgreSQL's advisory locks for speed and reliability.
Healthy across all four use cases
Permissive license, no critical CVEs, actively maintained — safe to depend on.
Has a license, tests, and CI — clean foundation to fork and modify.
Documented and popular — useful reference codebase to read through.
No critical CVEs, sane security posture — runnable as-is.
- ✓Last commit 4mo ago
- ✓17 active contributors
- ✓MIT licensed
Show 4 more →Show less
- ✓CI configured
- ✓Tests present
- ⚠Slowing — last commit 4mo ago
- ⚠Concentrated ownership — top contributor handles 62% of recent commits
Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests
Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.
Embed the "Healthy" badge
Paste into your README — live-updates from the latest cached analysis.
[](https://repopilot.app/r/que-rb/que)Paste at the top of your README.md — renders inline like a shields.io badge.
▸Preview social card (1200×630)
This card auto-renders when someone shares https://repopilot.app/r/que-rb/que on X, Slack, or LinkedIn.
Onboarding doc
Onboarding: que-rb/que
Generated by RepoPilot · 2026-05-10 · Source
🤖Agent protocol
If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:
- Verify the contract. Run the bash script in Verify before trusting
below. If any check returns
FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding. - Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
- Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/que-rb/que shows verifiable citations alongside every claim.
If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.
🎯Verdict
GO — Healthy across all four use cases
- Last commit 4mo ago
- 17 active contributors
- MIT licensed
- CI configured
- Tests present
- ⚠ Slowing — last commit 4mo ago
- ⚠ Concentrated ownership — top contributor handles 62% of recent commits
<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>
✅Verify before trusting
This artifact was generated by RepoPilot at a point in time. Before an
agent acts on it, the checks below confirm that the live que-rb/que
repo on your machine still matches what RepoPilot saw. If any fail,
the artifact is stale — regenerate it at
repopilot.app/r/que-rb/que.
What it runs against: a local clone of que-rb/que — the script
inspects git remote, the LICENSE file, file paths in the working
tree, and git log. Read-only; no mutations.
| # | What we check | Why it matters |
|---|---|---|
| 1 | You're in que-rb/que | Confirms the artifact applies here, not a fork |
| 2 | License is still MIT | Catches relicense before you depend on it |
| 3 | Default branch master exists | Catches branch renames |
| 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code |
| 5 | Last commit ≤ 159 days ago | Catches sudden abandonment since generation |
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of que-rb/que. If you don't
# have one yet, run these first:
#
# git clone https://github.com/que-rb/que.git
# cd que
#
# Then paste this script. Every check is read-only — no mutations.
set +e
fail=0
ok() { echo "ok: $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }
# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
echo "FAIL: not inside a git repository. cd into your clone of que-rb/que and re-run."
exit 2
fi
# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "que-rb/que(\\.git)?\\b" \\
&& ok "origin remote is que-rb/que" \\
|| miss "origin remote is not que-rb/que (artifact may be from a fork)"
# 2. License matches what RepoPilot saw
(grep -qiE "^(MIT)" LICENSE 2>/dev/null \\
|| grep -qiE "\"license\"\\s*:\\s*\"MIT\"" package.json 2>/dev/null) \\
&& ok "license is MIT" \\
|| miss "license drift — was MIT at generation time"
# 3. Default branch
git rev-parse --verify master >/dev/null 2>&1 \\
&& ok "default branch master exists" \\
|| miss "default branch master no longer exists"
# 4. Critical files exist
test -f "lib/que.rb" \\
&& ok "lib/que.rb" \\
|| miss "missing critical file: lib/que.rb"
test -f "lib/que/job.rb" \\
&& ok "lib/que/job.rb" \\
|| miss "missing critical file: lib/que/job.rb"
test -f "lib/que/worker.rb" \\
&& ok "lib/que/worker.rb" \\
|| miss "missing critical file: lib/que/worker.rb"
test -f "lib/que/connection.rb" \\
&& ok "lib/que/connection.rb" \\
|| miss "missing critical file: lib/que/connection.rb"
test -f "lib/que/locker.rb" \\
&& ok "lib/que/locker.rb" \\
|| miss "missing critical file: lib/que/locker.rb"
# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 159 ]; then
ok "last commit was $days_since_last days ago (artifact saw ~129d)"
else
miss "last commit was $days_since_last days ago — artifact may be stale"
fi
echo
if [ "$fail" -eq 0 ]; then
echo "artifact verified (0 failures) — safe to trust"
else
echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/que-rb/que"
exit 1
fi
Each check prints ok: or FAIL:. The script exits non-zero if
anything failed, so it composes cleanly into agent loops
(./verify.sh || regenerate-and-retry).
⚡TL;DR
Que is a high-performance PostgreSQL-backed job queue for Ruby that uses advisory locks instead of SELECT FOR UPDATE, eliminating lock contention and disk I/O bottlenecks. It guarantees ACID-protected job execution by leveraging PostgreSQL's transactional guarantees, allowing jobs to be queued atomically with application data and recovered safely if a worker process crashes. Monolithic gem structure: lib/que/job.rb handles job lifecycle, lib/que/locker.rb manages advisory locks, lib/que/listener.rb listens for job availability via LISTEN/NOTIFY, lib/que/active_job/ and lib/que/active_record/ provide framework integrations, lib/que/migrations/1-7/ contain versioned PostgreSQL schema SQL files, and lib/que/command_line_interface.rb wraps the CLI entrypoint (bin/que).
👥Who it's for
Ruby on Rails and Sequel developers who need reliable background job processing without Redis/RabbitMQ dependencies, especially those handling mission-critical operations where job loss or duplication during crashes is unacceptable, and who already run PostgreSQL in production.
🌱Maturity & risk
Production-ready and actively maintained. The repo shows semantic versioning (Que 2.x referenced in README), comprehensive test coverage via GitHub Actions (.github/workflows/tests.yml), and 7 numbered migrations indicating stable schema evolution. The codebase is substantial (335K Ruby, 13K PLpgSQL) with clear separation of concerns and both ActiveRecord and Sequel adapter support.
Low risk for production use but single-maintainer concerns typical of smaller gems. PostgreSQL version constraints should be verified (migrations suggest multi-version support). The PLpgSQL migration functions (13K lines) are performance-critical and require careful review on updates. No obvious deprecated dependencies visible, but check Gemfile for Rails/PG version constraints before upgrading.
Active areas of work
No specific PR/milestone data visible in file list, but 7 numbered migrations indicate ongoing schema improvements and bug fixes. The Dockerfile and docker-compose.yml suggest active development with containerized testing. Check GitHub Actions workflow (.github/workflows/tests.yml) and recent commits for current sprint activity.
🚀Get running
git clone https://github.com/que-rb/que.git && cd que && bundle install && auto/test to run the test suite (uses postgres-14 per auto/test-postgres-14). Use docker-compose up if Docker is preferred.
Daily commands: Locally: bundle exec que -w 4 (4 workers) or auto/test to run tests. Docker: docker-compose up spins up PostgreSQL and the queue. Migrations run via Que.migrate! or rake que:migrate (must be called before workers start).
🗺️Map of the codebase
lib/que.rb— Main entry point and public API; defines Que module and core methods for enqueueing and managing jobs.lib/que/job.rb— Core Job abstraction; defines the job lifecycle, enqueueing, locking, and execution logic.lib/que/worker.rb— Worker thread implementation that fetches and executes jobs from PostgreSQL advisory locks.lib/que/connection.rb— PostgreSQL connection abstraction; manages communication with the database and advisory lock operations.lib/que/locker.rb— PostgreSQL advisory lock manager; implements the core locking mechanism that differentiates Que from other queues.lib/que/migrations.rb— Database schema and migration management; defines the que_jobs table structure and triggers.lib/que/job_buffer.rb— In-memory buffer for enqueuing multiple jobs atomically within transactions.
🛠️How to make changes
Create a Custom Job Class
- Define a class inheriting from Que::Job and override the
runmethod with job logic. (lib/que/job.rb) - Set optional class attributes like
queue,priority, andrun_atbefore enqueueing. (lib/que/job.rb) - Enqueue an instance using
MyJob.enqueue(arg1, arg2)orQue.enqueue(MyJob, arg1, arg2). (lib/que.rb)
Add Custom Job Error Handling & Retries
- Override the
runmethod in your Job subclass and wrap logic in begin/rescue blocks. (lib/que/job.rb) - Call
self.retry_in(interval)or set error_count and retry_at attributes to defer execution. (lib/que/job.rb) - Optionally register error handlers via
Que.error_handler = proc { |error, job| ... }in initialization. (lib/que/utils/error_notification.rb)
Configure Que for a New Rails App
- Add
gem 'que'to Gemfile and runbundle install. (que.gemspec) - Run
rails generate que:installto create initializer and run migrations. (lib/que/rails/railtie.rb) - Configure Que in
config/initializers/que.rbwith queue names, worker count, and log level. (lib/que.rb) - Start workers via
bundle exec queor as part of Procfile for production. (bin/que)
Integrate Que with ActiveJob
- Set
config.active_job.queue_adapter = :quein Rails application config. (lib/que/active_job/extensions.rb) - Define ActiveJob job classes normally; Que will serialize and enqueue them. (
lib/que/active_job/extensions.rb) - Access Que-specific job metadata via job.que_attrs (priority, queue, run_at) in perform method. (
lib/que/active_job/extensions.rb)
🔧Why these technologies
- PostgreSQL Advisory Locks — Enables in-memory, non-blocking job locks without disk I/O; workers don't block each other, allowing high throughput under load.
- PostgreSQL LISTEN/NOTIFY — Real-time job notifications eliminate constant polling; workers wake immediately when jobs are enqueued.
- Ruby Threads — Multiple worker threads in a single process; efficient for I/O-bound job execution with simplified deployment.
- ActiveRecord & Sequel Support — Broad ORM compatibility allows Que to integrate seamlessly into existing Rails and non-Rails codebases.
- ActiveJob Adapter — Standard Rails job interface; users can switch queues without rewriting job classes.
⚖️Trade-offs already made
-
PostgreSQL-only; no Redis or RabbitMQ support
- Why: PostgreSQL advisory locks are the core advantage; adding other backends would dilute the unique value proposition.
- Consequence: Requires PostgreSQL as a hard dependency; users with legacy systems on MySQL cannot adopt Que.
-
In-process workers (threads) rather than separate processes
- Why: Simpler deployment, lower operational overhead, no inter-process communication needed.
- Consequence: Workers share Ruby VM memory; less isolation if one worker crashes or consumes memory badly; not ideal for CPU-intensive jobs.
-
No built-in job deduplication or prioritization algorithm
- Why: Keep scope minimal; priority is a simple numeric field, dedup is application logic.
- Consequence: Applications must implement dedup themselves; may lead to duplicate work in race conditions.
-
Jobs stored in PostgreSQL, not separate queue store
- Why: ACID guarantees; job enqueue is atomic with business logic; no risk of lost jobs.
- Consequence: Queue scalability is bounded by PostgreSQL write throughput; not suitable for billions of jobs.
🚫Non-goals (don't propose these)
- Does not support multiple queue backends (Redis, RabbitMQ, etc.); PostgreSQL-only.
- Does not provide job scheduling (cron-like); only delayed execution via run_at.
- Does not handle inter-process distributed workers; workers are threads within one Ruby process.
- Does not provide a web UI for job monitoring; that is left to external tools.
- Does not support job batching or bulk result collection; jobs execute independently.
🪤Traps & gotchas
PostgreSQL must be running and accessible (check DATABASE_URL env var or Que.connection config). Advisory locks require exclusive database access during migrations. The LISTEN/NOTIFY mechanism depends on PostgreSQL connection staying open — connection pooling misconfiguration silently breaks job polling. Job classes must be loadable in the worker process (require 'app/jobs/*' needed). Schema migrations are sequential (1–7) and cannot be skipped. Ruby Process.kill signals (SIGTERM/SIGINT) must be handled gracefully to prevent job abandonment.
🏗️Architecture
💡Concepts to learn
- PostgreSQL Advisory Locks — Core locking mechanism Que uses instead of SELECT FOR UPDATE; understanding their memory-based nature explains Que's performance advantage and the risks if lock state is lost
- LISTEN/NOTIFY (PostgreSQL Async Notifications) — Que uses this to wake idle workers when jobs arrive instead of polling; critical to understanding the listener.rb architecture and why connection handling is fragile
- ACID Guarantees & Transactional Atomicity — Que's core value proposition — queuing jobs within application transactions so job state stays synchronized with data; explains why ActiveRecord integration is non-trivial
- Work Stealing & Lock-Free Concurrency Patterns — Multiple workers competing for advisory locks on the same job table requires understanding how PostgreSQL serializes lock requests; explains the 'no blocking' behavior and throughput characteristics
- Job State Machines (queued → locked → finished/retry) — Jobs transition through states stored in PostgreSQL; understanding the state table schema (migrations/7) and when transitions happen is essential for debugging stuck jobs
- Ruby Thread Pools & Multithreading — Que's worker process uses a thread pool (locker.rb) to run multiple jobs concurrently in a single process; requires understanding Ruby GIL limitations and thread-safety of database adapters
- Database Connection Pooling — Que's connection_pool.rb and active_record/connection.rb manage multiple PostgreSQL connections across threads; misconfiguration (too few connections) causes worker stalls
🔗Related repos
resque/resque— Redis-backed job queue; direct competitor solving the same problem but with different storage and consistency guaranteescollectiveidea/delayed_job— Legacy RDBMS-backed queue predating Que; lacks advisory lock optimization but inspired Que's database-native approachrails/rails— ActiveJob framework that Que integrates with via lib/que/active_job/; required for Rails users of Queseamusabshere/sequel— Database toolkit that Que officially supports as alternative to ActiveRecord for connection managementpostgres/postgres— PostgreSQL source; advisory lock implementation (pg_advisory_lock) and LISTEN/NOTIFY are core Que dependencies
🪄PR ideas
To work on one of these in Claude Code or Cursor, paste:
Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.
Add integration tests for Sequel ORM adapter in CI pipeline
The repo has lib/que/sequel/model.rb and lib/que/active_record/ support, but .github/workflows/tests.yml likely only tests ActiveRecord integration. Sequel is a first-class adapter but lacks dedicated test coverage in CI. This would ensure Sequel users get the same reliability guarantees and catch regressions early.
- [ ] Review current test matrix in .github/workflows/tests.yml to confirm Sequel tests are missing or minimal
- [ ] Create a new test job in the workflow that sets up Que with Sequel instead of ActiveRecord
- [ ] Add Sequel-specific integration tests (e.g., job enqueueing, locking, error handling) mirroring ActiveRecord tests
- [ ] Ensure PostgreSQL 14+ compatibility per auto/test-postgres-14 script
Add comprehensive error handling documentation with code examples in docs/
lib/que/utils/error_notification.rb exists but there's no specific docs file explaining error notification strategies, middleware patterns, or how to integrate with Sentry/Rollbar. The README is incomplete (cuts off mid-sentence). New contributors and users need clear guidance on production error handling.
- [ ] Create docs/error_handling.md covering error_notification.rb functionality
- [ ] Document the Middleware system (lib/que/utils/middleware.rb) with before/after/error hooks examples
- [ ] Add code examples for integrating with common error tracking services (Sentry, Rollbar, Honeybadger)
- [ ] Reference error handling in docs/README.md with links to the new guide
Add comprehensive tests for lib/que/connection_pool.rb with edge cases
Connection pooling is critical for production reliability, but there's no visible dedicated test file for connection_pool.rb. Edge cases like connection exhaustion, pool timeout, reconnection after failure, and concurrent access patterns need explicit test coverage to prevent production incidents.
- [ ] Create spec/que/connection_pool_spec.rb (or test/que/connection_pool_test.rb depending on test structure)
- [ ] Add tests for: pool size limits, concurrent thread access, connection checkout/return, timeout behavior, stale connection recovery
- [ ] Test interaction with both ActiveRecord and Sequel connection models (lib/que/active_record/connection.rb patterns)
- [ ] Ensure tests cover the behavior documented in lib/que/connection.rb and lib/que/command_line_interface.rb pool options
🌿Good first issues
- Add per-job timeout enforcement in lib/que/job.rb — currently jobs can run indefinitely; implement max_runtime_seconds with Thread#kill and proper cleanup.
- Expand lib/que/active_job/extensions.rb to support ActiveJob::Serializers for custom job argument types (currently assumes JSONB-serializable types).
- Add comprehensive error context logging to lib/que/locker.rb advisory lock loop — currently silent failures on lock acquisition if PostgreSQL drops; add exponential backoff with logging.
⭐Top contributors
Click to expand
Top contributors
- @ZimbiX — 62 commits
- @oeoeaio — 14 commits
- @tomgi — 3 commits
- @kevinrobayna — 3 commits
- @mnbbrown — 3 commits
📝Recent commits
Click to expand
Recent commits
caa8b25— Fix broken test for Test: Ruby 3.0, Rails 6.0 + 6.1, PostgreSQL 14 (#444) (lee-treehouse)fbd57fd— Merge pull request #443 from lee-treehouse/update-dockerfile (ZimbiX)751c304— use bookworm instead of buster since buster is past EOL and won't npm install https://wiki.debian.org/DebianReleases#Ver (lee-treehouse)17fb2c3— Changelog: Add entry for version 2.4.1 (oeoeaio)0cf3351— Update version number to 2.4.1 (oeoeaio)f87b462— Merge pull request #423 from tomgi/activerecord_deprecation_warning (oeoeaio)c4dead8— Fix activerecord 7.1 and 7.2 deprecations (tomgi)ce869a7— Run tests on Rails 7.2 (tomgi)51403c0— Changelog: Add entry for version 2.4.0 (ZimbiX)9a1d634— Update version number to 2.4.0 (ZimbiX)
🔒Security observations
- High · Hardcoded Database Credentials in Docker Compose —
docker-compose.yml (lines with POSTGRES_USER, POSTGRES_PASSWORD, DATABASE_URL). The docker-compose.yml file contains hardcoded PostgreSQL credentials (username: 'que', password: 'que') in plain text. These credentials are also visible in the DATABASE_URL environment variable. This is a significant security risk as credentials should never be hardcoded in version-controlled files. Fix: Use environment variables or secrets management tools. Replace hardcoded credentials with references to .env files (which should be in .gitignore), Docker secrets, or external secret management systems. Example: DATABASE_URL should reference ${DATABASE_URL} from a .env file not committed to version control. - Medium · Exposed PostgreSQL Port in Development —
docker-compose.yml (db service, ports section). The PostgreSQL database service exposes port 5432 (mapped to 5697 on the host) in the docker-compose.yml file. This makes the database directly accessible from the host machine and potentially from external networks if not properly firewalled. Fix: Remove the ports mapping for the db service, or ensure it's only exposed for local development. If external access is needed, use a reverse proxy with proper authentication and encryption (TLS). For development-only setups, consider using named volumes and accessing the DB only through the dev service. - High · Weak Bundler Version Pinning Without Integrity Verification —
Dockerfile (line: RUN gem install bundler -v $RUBY_BUNDLER_VERSION). The Dockerfile pins bundler to version 2.4.22 but does not verify its integrity via checksums or GPG signatures. Combined with the Ruby base image pinning only by SHA (which is good), the bundler installation could be vulnerable to man-in-the-middle attacks or compromised gem sources. Fix: Implement bundler integrity verification. Use gem checksums or consider using bundle's native verification features. Alternatively, pre-install bundler in the base image and verify via SHA. Ensure Gemfile.lock is committed and bundler usesbundle install --frozento enforce locked versions. - Medium · Potential SQL Injection Risk in Database Operations —
lib/que/connection.rb, lib/que/job.rb, lib/que/migrations/*.sql files. The codebase handles PostgreSQL operations for a job queue system. While the file structure shows database migration files (up.sql, down.sql), without reviewing the actual SQL content and how queries are constructed in lib/que/connection.rb and lib/que/job.rb, there's a risk of SQL injection if raw SQL is constructed with user input or job parameters. Fix: Conduct a code review to ensure: 1) All SQL queries use parameterized queries or prepared statements, 2) Job parameters are properly escaped, 3) No raw string interpolation is used in SQL construction, 4) Test with SQL injection payloads in job arguments. - Medium · Missing Security Headers and Validation in JSON Serialization —
lib/que/utils/json_serialization.rb. The file lib/que/utils/json_serialization.rb handles JSON serialization for job data. Improper deserialization or validation could lead to code injection attacks, especially if untrusted data is deserialized or if Ruby object instantiation is allowed during JSON parsing. Fix: Ensure JSON parsing uses safe options: 1) UseJSON.parse()withoutobject_classorcreate_additions: false, 2) Validate and sanitize all deserialized data, 3) Implement strict schema validation for job arguments, 4) Avoid using YAML or Marshal for untrusted data, 5) Add tests for malicious JSON payloads. - Medium · Insufficient Input Validation in Command Line Interface —
lib/que/command_line_interface.rb. The lib/que/command_line_interface.rb file processes command-line arguments. Without proper validation, this could be vulnerable to injection attacks or unexpected behavior when processing user-supplied queue names, job types, or other parameters. Fix: Implement strict input validation for all CLI arguments. Use allowlists for queue names and job types. Sanitize any user input before passing to database queries. Add validation tests for malicious inputs. - Low · Ruby Deprecated Warnings Enabled in Production —
undefined. The Dockerfile setsRUBYOPT=-W:deprecated, enabling Fix: undefined
LLM-derived; treat as a starting point, not a security audit.
👉Where to read next
- Open issues — current backlog
- Recent PRs — what's actively shipping
- Source on GitHub
Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.