FastWorker

FastWorker vs RQ

Comparing FastWorker and RQ (Redis Queue) — simplicity, features, FastAPI integration, and when to choose each for Python background jobs.

Dipankar Sarkar · ·
rqredis-queuecomparisonpython

RQ (Redis Queue) is a deliberately minimalist Python task queue. If Celery feels heavy, RQ is often the next stop. FastWorker keeps RQ’s “just a queue” ethos but removes Redis from the picture — leaving you with a task queue that’s 100% Python processes.

The one-line summary

RQ keeps things simple by building on Redis. FastWorker keeps things simple by not needing Redis.

Both aim at the same target audience: Python teams who find Celery too much. FastWorker just pushes further.

Feature matrix

CapabilityFastWorkerRQ
External brokerNoneRedis required
Minimal services2–3 Python processes3–4 (app, RQ worker, Redis)
Setup time< 5 minutes~15 minutes
Built-in dashboardYes (auto-starts at :8080)rq-dashboard (separate package)
Async FastAPI clientYesNo (sync enqueue)
Priority queues4 levels, built-inMulti-queue workers
Worker discoveryAutomaticManual (workers listen on queue names)
Task chainsNoLimited (job dependencies)
Scheduled tasksNoVia rq-scheduler
Task persistenceIn-memoryRedis-backed (durable)
Retries with backoffManualRetry class
Job cancellationBasicSupported
OpenTelemetryBuilt-inManual instrumentation
Recommended scale1K–10K tasks/minSimilar

Deployment: side by side

RQ — minimal setup

# You need Redis running somewhere
docker run -p 6379:6379 redis:7

# In your Python code
from redis import Redis
from rq import Queue

q = Queue(connection=Redis())

def send_email(user_id):
    ...

q.enqueue(send_email, user_id=42)
# Worker process
rq worker

Three things to keep running: your app, an RQ worker, and Redis.

FastWorker — minimal setup

# mytasks.py
from fastworker import task

@task
def send_email(user_id: int) -> bool:
    ...
    return True
# One terminal
fastworker control-plane --task-modules mytasks
# In your app
await client.delay("send_email", 42)

Two things to keep running: your app and the control plane. No Redis.

Code: side by side

Enqueueing from FastAPI

# RQ
from fastapi import FastAPI
from redis import Redis
from rq import Queue

app = FastAPI()
q = Queue(connection=Redis(host="redis"))

@app.post("/signup")
async def signup(user_id: int):
    q.enqueue("tasks.send_email", user_id)   # sync call in async handler
    return {"ok": True}
# FastWorker
from fastapi import FastAPI
from fastworker import Client

app = FastAPI()
client = Client()

@app.on_event("startup")
async def _start():
    await client.start()

@app.post("/signup")
async def signup(user_id: int):
    await client.delay("send_email", user_id)   # async-native
    return {"ok": True}

Priority

# RQ — use separate queues
q_hi = Queue("high", connection=redis)
q_lo = Queue("low", connection=redis)
q_hi.enqueue(send_receipt, order_id)

# Worker listens to queues in order
# rq worker high normal low
# FastWorker — one queue, enum priorities
from fastworker.tasks.models import TaskPriority
await client.delay("send_receipt", order_id,
                   priority=TaskPriority.HIGH)

RQ leans on multi-queue workers for prioritization. FastWorker gives you four enum levels on a single queue.

Where RQ wins

  • Durable persistence. Jobs sit in Redis. If the worker crashes, they’re still there. FastWorker keeps the queue in memory.
  • rq-scheduler. For recurring / scheduled jobs, RQ has a good story via rq-scheduler.
  • Job cancellation. First-class.
  • Simpler mental model for Redis shops. If you already run Redis, RQ piggybacks on it for free.
  • Battle tested. RQ is mature and ships a lot of small conveniences FastWorker hasn’t built yet.

Where FastWorker wins

  • No Redis. The whole point of this comparison. If you don’t already run Redis, RQ adds one more service to your stack. FastWorker doesn’t.
  • Async FastAPI client. RQ’s enqueue is synchronous. It’s fast, but it still blocks your event loop briefly. FastWorker’s Client is async-native.
  • Built-in dashboard. rq-dashboard is a separate install. FastWorker’s GUI ships with the control plane and starts automatically.
  • Enum priorities. Using RQ’s multi-queue model for priorities is fine but requires you to think about queue names; FastWorker gives you four enum levels and a single interface.
  • Automatic worker discovery. Subworkers find the control plane on startup — no manual queue name list.

Which to choose

Choose RQ if:

  • You already run Redis and are happy to use it
  • You need durable queues (tasks must survive a worker crash)
  • You want rq-scheduler for recurring jobs
  • You need first-class job cancellation

Choose FastWorker if:

  • You don’t want to run Redis just for a task queue
  • You’re using FastAPI and want an async-native client
  • You want a web dashboard without installing rq-dashboard
  • You want enum priorities instead of multi-queue routing

Next steps

Frequently asked questions

Is RQ simpler than Celery?

Yes — RQ is explicitly designed to be a simple, Redis-backed alternative to Celery. FastWorker takes that same instinct one step further by dropping Redis entirely.

Does RQ work with FastAPI?

Yes, but RQ is synchronous by design. You call q.enqueue(...) from an async handler and it blocks the event loop briefly. FastWorker's client is async-native.

Can I keep using RQ and add FastWorker for specific jobs?

Yes. They don't conflict. A common pattern is running FastWorker for user-facing, latency-sensitive background tasks while keeping RQ for simpler long-tail jobs.