RepoPilotOpen in app →

jondot/sneakers

A fast background processing framework for Ruby and RabbitMQ

Healthy

Healthy across all four use cases

Use as dependencyHealthy

Permissive license, no critical CVEs, actively maintained — safe to depend on.

Fork & modifyHealthy

Has a license, tests, and CI — clean foundation to fork and modify.

Learn fromHealthy

Documented and popular — useful reference codebase to read through.

Deploy as-isHealthy

No critical CVEs, sane security posture — runnable as-is.

  • 13 active contributors
  • Distributed ownership (top contributor 39% of recent commits)
  • MIT licensed
Show 3 more →
  • CI configured
  • Tests present
  • Stale — last commit 2y ago

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.

Variant:
RepoPilot: Healthy
[![RepoPilot: Healthy](https://repopilot.app/api/badge/jondot/sneakers)](https://repopilot.app/r/jondot/sneakers)

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/jondot/sneakers on X, Slack, or LinkedIn.

Onboarding doc

Onboarding: jondot/sneakers

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:

  1. 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.
  2. 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.
  3. Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/jondot/sneakers 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

  • 13 active contributors
  • Distributed ownership (top contributor 39% of recent commits)
  • MIT licensed
  • CI configured
  • Tests present
  • ⚠ Stale — last commit 2y ago

<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 jondot/sneakers repo on your machine still matches what RepoPilot saw. If any fail, the artifact is stale — regenerate it at repopilot.app/r/jondot/sneakers.

What it runs against: a local clone of jondot/sneakers — 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 jondot/sneakers | 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 ≤ 712 days ago | Catches sudden abandonment since generation |

<details> <summary><b>Run all checks</b> — paste this script from inside your clone of <code>jondot/sneakers</code></summary>
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of jondot/sneakers. If you don't
# have one yet, run these first:
#
#   git clone https://github.com/jondot/sneakers.git
#   cd sneakers
#
# 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 jondot/sneakers and re-run."
  exit 2
fi

# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "jondot/sneakers(\\.git)?\\b" \\
  && ok "origin remote is jondot/sneakers" \\
  || miss "origin remote is not jondot/sneakers (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/sneakers.rb" \\
  && ok "lib/sneakers.rb" \\
  || miss "missing critical file: lib/sneakers.rb"
test -f "lib/sneakers/worker.rb" \\
  && ok "lib/sneakers/worker.rb" \\
  || miss "missing critical file: lib/sneakers/worker.rb"
test -f "lib/sneakers/runner.rb" \\
  && ok "lib/sneakers/runner.rb" \\
  || miss "missing critical file: lib/sneakers/runner.rb"
test -f "lib/sneakers/configuration.rb" \\
  && ok "lib/sneakers/configuration.rb" \\
  || miss "missing critical file: lib/sneakers/configuration.rb"
test -f "lib/sneakers/publisher.rb" \\
  && ok "lib/sneakers/publisher.rb" \\
  || miss "missing critical file: lib/sneakers/publisher.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 712 ]; then
  ok "last commit was $days_since_last days ago (artifact saw ~682d)"
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/jondot/sneakers"
  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).

</details>

TL;DR

Sneakers is a high-performance background job processing framework for Ruby that uses RabbitMQ as its message broker. It enables developers to process long-running or CPU-intensive tasks asynchronously by defining Workers that consume messages from RabbitMQ queues, with built-in support for retries, error handling, metrics, and multiple deployment patterns. Monolithic gem structure: lib/sneakers/ contains the core engine (worker.rb, runner.rb, spawner.rb), lib/sneakers/middleware/ for request processing, lib/sneakers/metrics/ for monitoring integrations (Statsd, NewRelic, logging), lib/sneakers/handlers/ for retry/error strategies, and examples/ with runnable worker patterns. CLI entry point is bin/sneakers backed by lib/sneakers/cli.rb.

👥Who it's for

Ruby on Rails and general Ruby application developers who need to offload background work (email sending, image processing, data analytics) from their main application thread without building custom RabbitMQ infrastructure. DevOps engineers managing production workloads also use it for reliable job processing at scale.

🌱Maturity & risk

This project is production-ready but abandoned by original maintainer. The README explicitly warns users to migrate to ruby-amqp/kicks, the community-maintained fork. The repo has mature patterns (122K lines of Ruby, Docker setup, CI/CD pipeline in .github/workflows/ci.yml), but the original author no longer maintains it and exclusive control of the RubyGems package prevents updates.

High risk for new projects: The original maintainer abandoned this repo (see GitHub issue #452), and the RubyGems gem is locked under their exclusive control, preventing community releases. Dependency on RabbitMQ adds operational complexity. No visible recent commits or active issue triage suggests stalled maintenance. Recommend adopting ruby-amqp/kicks instead for new work.

Active areas of work

The project is in maintenance-only mode post-abandonment. CI pipeline exists (.github/workflows/ci.yml) but no recent feature work is visible. Community forked to ruby-amqp/kicks to continue development. No active PRs or milestones are indicated in the provided repo data.

🚀Get running

git clone https://github.com/jondot/sneakers.git
cd sneakers
bundle install
docker-compose up  # Start RabbitMQ locally
bundle exec sneakers work examples/benchmark_worker.rb --require examples/boot.rb

Daily commands:

bundle exec sneakers work MyWorkerClass --require boot.rb  # Production
bundle exec rake  # Run tests
docker-compose up  # Start RabbitMQ for local dev

🗺️Map of the codebase

  • lib/sneakers.rb — Entry point and main module definition; sets up global configuration and includes all core components.
  • lib/sneakers/worker.rb — Core abstraction for background job workers; every job processor extends this class and defines work() method.
  • lib/sneakers/runner.rb — Main orchestrator that manages worker lifecycle, message consumption loop, and signal handling.
  • lib/sneakers/configuration.rb — Centralized configuration management for RabbitMQ connection, queue settings, and framework behavior.
  • lib/sneakers/publisher.rb — Public API for publishing messages to RabbitMQ queues; used by application code to enqueue jobs.
  • lib/sneakers/queue.rb — Wraps RabbitMQ queue abstraction with message acknowledgment, rejection, and requeue logic.
  • lib/sneakers/cli.rb — Command-line interface for starting worker processes; parses config files and invokes runner.

🛠️How to make changes

Create a new background worker

  1. Extend Sneakers::Worker and define the work() method (lib/sneakers/worker.rb)
  2. Declare from_queue() and set handler options (maxretry, etc) (lib/sneakers/worker.rb)
  3. Return :ok, :requeue, or :error from work() to control message handling (lib/sneakers/worker.rb)
  4. Register worker in sneakers.conf.rb or load explicitly in runner (examples/sneakers.conf.rb.example)

Add a custom error handler / retry strategy

  1. Extend Sneakers::Handlers and implement handle() method (lib/sneakers/handlers/maxretry.rb)
  2. Reference handler in worker via handler: MyHandler configuration (lib/sneakers/worker.rb)
  3. Implement retry logic, dead-letter routing, or custom exception handling (lib/sneakers/handlers/maxretry.rb)

Integrate custom metrics backend

  1. Create new metrics class extending Sneakers::Metrics base interface (lib/sneakers/metrics/statsd_metrics.rb)
  2. Implement increment(), timing(), and gauge() methods (lib/sneakers/metrics/statsd_metrics.rb)
  3. Register in configuration via Sneakers.configure { |c| c.metrics = MyMetrics.new } (lib/sneakers/configuration.rb)

Publish a message to a queue

  1. Use Sneakers::Publisher.publish(payload, options) in your application code (lib/sneakers/publisher.rb)
  2. Specify routing_key, content_type, and other envelope metadata (lib/sneakers/publisher.rb)
  3. Worker with matching from_queue() will consume the message (lib/sneakers/worker.rb)

🔧Why these technologies

  • RabbitMQ — Provides durable, distributed message queuing with advanced routing (topic exchanges, dead-letter queues) and AMQP protocol for reliable job delivery.
  • Ruby Threads & Bunny — Bunny gem provides native AMQP client; threads allow concurrent message processing from multiple queues in a single process.
  • Concerns (Logging, Metrics) as Mixins — DRY pattern to inject observability into workers without polluting business logic; worker inherits logging and metrics capabilities.
  • Handler Strategy Pattern — Decouples retry and error-recovery logic from core worker; supports swappable strategies (maxretry, oneshot, custom).

⚖️Trade-offs already made

  • Single-process workers with thread pool vs. multi-process

    • Why: Simpler memory footprint and state sharing; better for I/O-bound workloads; matches Rails ecosystem patterns.
    • Consequence: CPU-intensive workloads may not scale linearly; GIL contention on heavy computation; no true parallelism within one process.
  • Manual ack/nack/requeue vs. auto-ack

    • Why: Prevents message loss on worker crash; supports dead-letter routing for failed jobs.
    • Consequence: Developer must explicitly handle return values (:ok, :requeue, :error); forgotten error handling can deadlock queues.
  • Configuration via Ruby code + CLI flags vs. environment variables only

    • Why: Allows dynamic config, conditional queue binding, and complex logic in sneakers.conf.rb.
    • Consequence: Less portable across container orchestration; sneakers.conf.rb is a code file, not pure config.
  • Metrics as pluggable backends (StatsD, NewRelic, Null, Logging)

    • Why: Avoids hard dependency on monitoring vendor; supports dev/test with null metrics.
    • Consequence: Requires explicit initialization per environment; no built-in Prometheus endpoint (though community integrations exist).

🚫Non-goals (don't propose these)

  • Real-time message ordering guarantees (RabbitMQ FIFO is optional, not enforced)
  • Transactional outbox pattern (no built-in exactly-once semantics across databases and queues)
  • Scheduled/delayed job persistence (external scheduler like Sidekiq/Resque required for cron jobs)
  • WebUI dashboard or job introspection API (no built-in admin panel)
  • Authentication/authorization for queue access (delegated to RabbitMQ vhost/user model)

🪤Traps & gotchas

RabbitMQ must be running: docker-compose.yml shows local dev setup required. Thread safety: Worker.work() runs in thread pool (spawner.rb), so instance variables are not safe—use thread-local storage or side-effects only. Ack semantics critical: Must call ack!, nack!, or reject! in work() or message will timeout; forgotten ack causes queue backlog. Config timing: Sneakers.configure block must run before Worker class definitions or queue binding fails. No Rails autoload: --require boot.rb explicit require needed since sneakers doesn't integrate Rails boot hooks.

🏗️Architecture

💡Concepts to learn

  • Message Acknowledgment (Ack/Nack/Reject) — Sneakers workers must explicitly acknowledge, negative-acknowledge, or reject messages to signal RabbitMQ whether processing succeeded or failed—missing this causes deadlettering and queue buildup, critical for production reliability
  • Thread Pool / Spawner Pattern — Sneakers uses lib/sneakers/spawner.rb to manage a pool of worker threads processing messages concurrently; understanding thread-safety and configurable concurrency levels is essential for tuning performance
  • Middleware Pipeline — lib/sneakers/middleware/ implements a request-lifecycle hook system similar to Rack middleware; extensibility point for logging, metrics, authentication without modifying core worker logic
  • Dead Letter Queue (DLQ) / Max Retry Handler — lib/sneakers/handlers/maxretry.rb implements exponential backoff and dead-lettering; understanding RabbitMQ DLQ patterns prevents message loss and enables failure alerting
  • Content-Type and Content-Encoding Negotiation — lib/sneakers/content_type.rb and content_encoding.rb handle message serialization format (JSON, MessagePack, etc.); critical for interoperability with non-Ruby publishers
  • Pluggable Metrics Backends — lib/sneakers/metrics/ abstracts metrics collection (Statsd, NewRelic, logging); allows swapping monitoring without code changes—demonstrates dependency injection pattern
  • Worker Class Mixin / DSL Design — lib/sneakers/worker.rb uses Ruby mixins and class-level DSL (from_queue, prefetch, ack: true) to define worker behavior declaratively; understanding this pattern is core to using the framework
  • ruby-amqp/kicks — Official community-maintained fork of Sneakers after original abandoned; this is where active development moved
  • ruby-amqp/bunny — RabbitMQ client library that Sneakers wraps; understanding Bunny channels/queues essential for troubleshooting
  • sidekiq/sidekiq — Competing background job framework for Ruby; uses Redis instead of RabbitMQ, useful for comparing patterns
  • collectiveidea/delayed_job — Lighter-weight alternative job queue; shows different approach to async processing in Rails ecosystem
  • ruby-amqp/amq-protocol — Low-level AMQP protocol library; Bunny depends on this; relevant for debugging message format issues

🪄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 comprehensive integration tests for lib/sneakers/handlers/maxretry.rb

The maxretry handler is a critical component for production reliability, but there are no dedicated spec files for lib/sneakers/handlers/ visible in the test structure. This would ensure retry logic, backoff strategies, and failure scenarios are properly tested before the migration to the new 'kicks' project.

  • [ ] Create spec/sneakers/handlers/maxretry_spec.rb with tests for max retry limits
  • [ ] Add tests for exponential backoff behavior and retry delays
  • [ ] Test dead-letter queue behavior when max retries are exceeded
  • [ ] Add edge case tests (e.g., zero retries, negative values, concurrent retries)

Add missing tests for lib/sneakers/publisher.rb

The publisher is a core component for sending messages to RabbitMQ, but the test file spec/sneakers/publisher_spec.rb appears to exist with minimal coverage. The publisher handles content encoding, routing, and message delivery which are critical paths.

  • [ ] Expand spec/sneakers/publisher_spec.rb to cover all content encoding types (gzip, deflate, identity)
  • [ ] Add tests for publisher routing with different exchange types
  • [ ] Test error handling for connection failures and channel closures
  • [ ] Add tests for batch publishing and acknowledgment handling

Create comprehensive spec file for lib/sneakers/middleware/config.rb

The middleware configuration is foundational to the sneakers request pipeline, but no test file is visible in spec/sneakers/middleware/. This gap makes it difficult to ensure middleware chain initialization, ordering, and configuration propagation work correctly.

  • [ ] Create spec/sneakers/middleware/config_spec.rb
  • [ ] Add tests for middleware chain initialization and execution order
  • [ ] Test middleware configuration inheritance and override behavior
  • [ ] Add tests for error handling when middleware configuration is invalid
  • [ ] Test integration with worker lifecycle (setup/teardown)

🌿Good first issues

  • Add integration tests for lib/sneakers/handlers/oneshot.rb—it exists but has no visible test coverage in spec/ directory; write tests following maxretry.rb test patterns
  • Document the middleware chain execution order in lib/sneakers/middleware/config.rb with inline examples showing how to hook custom middleware (currently undocumented API)
  • Add missing error_reporter.rb integration examples to examples/—the file exists but no example worker shows how to use ErrorReporter for custom alerting

Top contributors

Click to expand

📝Recent commits

Click to expand
  • 9780692 — README: mention the user community decision in jondot/sneakers#452 (michaelklishin)
  • 2182270 — Merge pull request #474 from thanosbellos/master (michaelklishin)
  • 4f64fd6 — Use Rails.autoloaders.zeitwerk_enabled? instead of deprecated Rails.application.config.autoloader (thanosbellos)
  • 803d60d — Merge pull request #472 from MatthewRDodds/use-application-configured-loader (michaelklishin)
  • d7b2edb — Check application's configured loader rather than looking at whether the newer loader is defined (Matthew Dodds)
  • 1039868 — Actions: silence a deprecation warning (michaelklishin)
  • 837f4cc — Mention that Sneakers main targets Ruby 3.0+ now (michaelklishin)
  • 63fb84f — Merge pull request #469 from wwwermishel/master (michaelklishin)
  • ced9d28 — Actions: target Ruby 3.0-3.2 (michaelklishin)
  • 6817ed0 — Using File#exist? method instead of File#exists? / In ruby 3 File#exists? was removed (omn)

🔒Security observations

  • Critical · Outdated Ruby Version in Dockerfile — Dockerfile (line 1). The Dockerfile uses Ruby 2.4-alpine, which was released in 2018 and has reached end-of-life. Ruby 2.4 no longer receives security patches, making the application vulnerable to known exploits. Fix: Upgrade to Ruby 3.1+ or at minimum Ruby 2.7. Update the base image to 'FROM ruby:3.2-alpine' or later.
  • High · Default RabbitMQ Credentials in docker-compose — docker-compose.yml (line 18-19, environment variable). The docker-compose.yml exposes RabbitMQ with default credentials (guest:guest) and no authentication changes. The RabbitMQ management UI is exposed on port 15672 without password protection. Fix: Change default RabbitMQ credentials, disable guest user in production, use environment variables for secrets, and restrict management UI access with proper authentication and network policies.
  • High · Exposed RabbitMQ Management Port — docker-compose.yml (line 21). RabbitMQ management interface is exposed on port 15672 without any access controls or firewall restrictions in docker-compose configuration. Fix: Remove port mapping for 15672 or restrict it to localhost only. In production, use network policies and firewall rules to limit access to management interface.
  • High · Exposed Redis Port Without Authentication — docker-compose.yml (line 24). Redis is exposed on port 6379 without password authentication. This service is accessible from the network without credentials. Fix: Configure Redis with requirepass authentication. In production, restrict Redis to internal networks only and use strong authentication credentials.
  • Medium · Missing Security Headers and Input Validation — lib/sneakers/worker.rb, lib/sneakers/handlers/. The codebase processes RabbitMQ messages through workers. Without evidence of input validation and sanitization in worker implementations, there is a risk of injection attacks (deserialization, command injection). Fix: Implement strict input validation and sanitization for all message payloads. Use safe deserialization practices and avoid eval() or dangerous YAML parsing.
  • Medium · Project Abandoned and Migrated — README.md. The README indicates the project has been abandoned by the original author and the community has migrated to ruby-amqp/kicks. Using an unmaintained gem introduces security and compatibility risks as vulnerabilities won't be patched. Fix: Migrate to the new maintained fork 'ruby-amqp/kicks' instead of using the abandoned sneakers gem.
  • Medium · Hardcoded Example Configuration File — examples/sneakers.conf.rb.example. The example configuration file 'examples/sneakers.conf.rb.example' may contain hardcoded credentials or sensitive configuration that could be accidentally copied into production. Fix: Ensure example files never contain real credentials. Use environment variables and secrets management systems for configuration. Add *.conf.rb (without .example) to .gitignore.
  • Medium · Build Dependencies Not Cleaned Up — Dockerfile (lines 4-7). In the Dockerfile, build dependencies are installed (build-base, ruby-dev, etc.) but not explicitly removed after compilation, increasing the final image size and attack surface. Fix: Remove build dependencies after bundle install: 'apk del build_deps' or use multi-stage Docker builds to reduce final image size.
  • Low · Missing .env File Protection — docker-compose.yml, Configuration management. While no .env file is present in the repo, environment variables are being used. There's no evidence of .env.example or documentation about required secrets management. Fix: Create a .env.example file documenting all required environment variables. Ensure .env files are in .gitignore (already present based on file listing).
  • Low · Git History Exposure via Docker Volume — undefined. The docker-compose.yml mounts the entire current directory as a volume (volumes: - .:/sneakers), which includes .git Fix: undefined

LLM-derived; treat as a starting point, not a security audit.


Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.

Healthy signals · jondot/sneakers — RepoPilot