ConquerManage
A small job queue. An Express producer pushes tasks into Redis, and a pool of workers picks them up, retries failures, and dead-letters the ones that keep failing.

Overview
I first wrote this in Go, then rewrote it in TypeScript to understand how the same producer/worker pattern works on Node's event loop. The producer takes POST /enqueue, validates the task and puts it in a Redis list. The worker service runs several loops that pull tasks and process them.
The task handlers (send_email, resize_image, generate_pdf) just log what they would do. The point was the queue, not the jobs.
Problem
Slow work like sending emails shouldn't block an HTTP request. It should go to the background, and if it fails it shouldn't just vanish.
Approach
Tasks get a UUID and are RPUSHed onto a list. Workers BLPOP them, so there's no busy polling. A failed task goes back on the queue with one fewer retry, and once it's out of retries it goes to a dead-letter list where I can inspect it later.
Architecture / how it works
- Each worker loop gets its own Redis connection. A blocking
BLPOPholds its connection while it waits, so loops sharing one client would just take turns. BLPOPblocks for at most 5s, then loops. There's no polling burning CPU, and a worker notices a shutdown within 5 seconds.- Concurrency comes from
WORKER_CONCURRENCY(default 3): N async loops started together. - Failed tasks go back on the queue with
retries - 1. At zero they're pushed totask_queue:dead. - On SIGINT or SIGTERM it stops taking new work, lets in-flight tasks finish, then closes Redis, with an 8s cap so it finishes before Docker's 10s kill.
- Validation per task type, e.g.
send_emailneedstoandsubject. - Docker Compose runs redis, the producer (:3000) and the worker (:3001, with
/healthand/metrics).
Tech stack
Outcomes
It runs end to end with Docker Compose (the gallery has a full run). The thing I didn't expect: BLPOP holds its connection while it waits, so real parallelism needs one Redis connection per worker loop.
Gallery

