Small distributed task processing system written in Go.
The API accepts jobs, stores them in PostgreSQL, pushes job IDs to Redis, and workers consume the queue and update job status.
- accepts jobs over HTTP
- lists recent jobs over HTTP
- stores job payloads and status in PostgreSQL
- uses Redis as the queue between API and workers
- retries temporary failures with backoff and sends final failures to a dead-letter queue
- runs workers concurrently
- exposes health and metrics endpoints
Client
-> API
-> PostgreSQL
-> Redis
-> Worker(s)
- Client sends a job to the API.
- API stores the job with status
queued. - API pushes the job ID to Redis.
- Worker reads the job ID from Redis.
- Worker marks the job as
running. - Worker retries temporary failures with backoff.
- Worker finishes the job as
completedor sends it to the dead-letter queue after the last failed attempt.
docker compose -f deploy/compose/docker-compose.yml up -d --buildServices:
- API:
http://localhost:8080 - Health:
http://localhost:8080/health - API metrics:
http://localhost:8080/metrics - Worker metrics:
http://localhost:9091/metrics
Create a job:
curl -s -X POST http://localhost:8080/jobs \
-H "Content-Type: application/json" \
-d '{"payload":{"type":"demo","value":123}}'Fetch a job:
curl -s http://localhost:8080/jobs/<job-id>List recent jobs:
curl -s http://localhost:8080/jobs?limit=10Retry example:
curl -s -X POST http://localhost:8080/jobs \
-H "Content-Type: application/json" \
-d '{"payload":{"type":"demo","fail_until_attempt":2,"duration_ms":250}}'You need PostgreSQL and Redis running locally.
API:
go run ./cmd/apiWorker:
go run ./cmd/workerDefault config:
DB_DSN=postgres://task:task@localhost:5432/task?sslmode=disableREDIS_ADDR=localhost:6379API_PORT=8080WORKER_COUNT=4WORKER_METRICS_PORT=9091MAX_ATTEMPTS=3RETRY_BASE_DELAY=1sRETRY_MAX_DELAY=10s
cmd/
api/
worker/
internal/
config/
db/
job/
observability/
queue/
retry/
deploy/
compose/
docker/
migrations/
- database schema is in
migrations/001_create_jobs.sql - Docker Compose runs the migration automatically
- payload supports
type,duration_ms,fail,fail_until_attempt, anderror
MIT