Forge is a highly concurrent, resilient distributed task queue built with Go and Redis Streams. It provides robust capabilities out of the box for handling asynchronous jobs, scaling workers, and managing failures seamlessly through automatic retries and a Dead-Letter Queue (DLQ).
If a worker crashes or fails, the task is automatically re-queued up to a configurable retry limit before being isolated to a dedicated Dead-Letter Queue (Forge_tasks_dlq) for inspection and manual replay.
| Feature | Description |
|---|---|
| Concurrent Worker Pool | Spin up a configurable pool of goroutines to process tasks in parallel without blocking. |
| Automatic Retries | Failing tasks are transparently re-queued up to a per-task MaxRetries limit. |
| Dead-Letter Queue | Poison-pill tasks that exhaust all retries are routed to an isolated DLQ stream for safe inspection. |
| DLQ Replay | Re-enqueue all DLQ tasks back into the main stream with a single API call β retries reset to zero. |
| Graceful Shutdown | Intercepts SIGINT/SIGTERM, stops the fetch loop, and lets in-flight workers drain cleanly before exiting. |
| Real-Time Event Stream | Server-Sent Events (SSE) endpoint broadcasts task lifecycle events via Redis Pub/Sub. |
| Prometheus Metrics | Exposes task throughput, failure rates, DLQ counts, processing duration, worker panics, and idempotency stats at /metrics. |
| Redis Streams Backed | Built on Redis 5.0+ Streams using XADD, XREADGROUP, and XACK β persistent, ordered, and consumer-group-aware. |
| Priority Queues | Route tasks to high/normal/low priority streams. Consumer reads high-priority first. |
| Idempotency Keys | Prevent duplicate task processing with Redis-backed idempotency checks (24h TTL). |
| Task Timeouts | Per-task timeout support via context.WithTimeout. |
| Rate Limiting | API endpoints protected with per-IP token bucket rate limiting. |
| Health Checks | GET /api/health returns Redis connectivity and uptime. |
| API Key Auth | DLQ replay endpoint protected by Bearer token authentication. |
| Redis Cluster | Optional Redis Cluster support for horizontal scaling. |
| Docker Ready | Multi-stage Dockerfile + docker-compose with Redis, Prometheus, and Grafana. |
| CI/CD Pipeline | GitHub Actions workflow with lint, test, build, and Docker image verification. |
| Testable Architecture | Interfaces for all dependencies β unit testable without a live Redis. |
Benchmarked on a single node against a local Redis instance (AMD Ryzen 5 3600, Windows):
| Metric | Result |
|---|---|
| Throughput | 13,356 tasks/sec (publish) |
| p99 Enqueue Latency | 582ms under 10,000 concurrent goroutines |
| Workers | 50 concurrent goroutines |
| Tasks | 10,000 concurrent enqueues |
| Total Time | ~0.75 seconds |
Run it yourself:
# Requires Redis running on localhost:6379
go test -v -run=^$ -bench=BenchmarkForgeQueue -benchtime=1x ./benchmarks/Producer (XADD)
β
βΌ
Redis Stream (Forge_tasks) βββ Forge_tasks_high (priority)
β βββ Forge_tasks (normal)
βΌ βββ Forge_tasks_low (priority)
Consumer Group (XREADGROUP)
β
βββ Idempotency Check (SET NX)
βββ Worker 1 βββΊ Process βββΊ XACK βββΊ β
Success
βββ Worker 2 βββΊ Process βββΊ Retry βββΊ Re-queue (up to MaxRetries)
βββ Worker N βββΊ Process βββΊ DLQ βββΊ Forge_tasks_dlq
All state changes βββΊ Redis Pub/Sub (Forge_events) βββΊ SSE API βββΊ Dashboard
- Interface-based:
StreamStore,EventPublisher,TaskProcessor,IdempotencyCheckerβ every dependency is injectable and mockable - Structured logging:
log/slogwith JSON output for production, human-readable for development - Configuration via env vars: All hardcoded values replaced with environment variables and sensible defaults
- Graceful everywhere: Context propagation from signal handler through fetcher, workers, API server, and metrics server
Forge/
βββ main.go # Entry point: config, wiring, signal handling
βββ config/
β βββ config.go # Environment-based configuration
βββ task/
β βββ task.go # Task & Event struct definitions
β βββ store.go # Interfaces: StreamStore, EventPublisher, TaskProcessor, IdempotencyChecker
βββ producer/
β βββ producer.go # Enqueues tasks via StreamStore
β βββ priority.go # Priority-aware producer (routes to _high/_low streams)
βββ consumer/
β βββ consumer.go # Worker pool: fetch, process, retry, DLQ
β βββ priority_consumer.go # Priority-aware consumer (reads high-first)
βββ api/
β βββ server.go # REST + SSE API server (graceful shutdown)
β βββ middleware.go # CORS, API key auth, panic recovery, rate limiting
βββ event/
β βββ publisher.go # Redis Pub/Sub event publisher
βββ redisadapter/
β βββ adapter.go # StreamStore implementation for Redis standalone
β βββ cluster.go # StreamStore implementation for Redis Cluster
β βββ idempotency.go # IdempotencyChecker implementation (SET NX)
βββ metrics/
β βββ metrics.go # Prometheus metric collectors
βββ tests/
β βββ integration_test.go # Integration tests (requires Redis)
βββ benchmarks/
β βββ benchmark_test.go # Producer-side benchmark
βββ dashboard/ # Next.js frontend
βββ docs/ # Deep-dive documentation guides
βββ Dockerfile # Multi-stage Go build
βββ docker-compose.yml # Redis + Prometheus + Grafana + Forge
βββ prometheus.yml # Prometheus scrape config
βββ .github/workflows/
βββ ci.yml # GitHub Actions CI pipeline
- Go 1.24+
- Docker & Docker Compose (for the local Redis / Prometheus / Grafana stack)
- Node.js 20+ (only if running the dashboard)
docker-compose up -dThis starts everything β Redis, Prometheus, Grafana, and Forge itself:
- Forge API on
http://localhost:8080 - Prometheus metrics on
http://localhost:2112/metrics - Prometheus UI on
http://localhost:9090 - Grafana on
http://localhost:3000(default:admin/admin)
docker-compose up -d redis prometheus grafanago run main.goOr with custom configuration:
REDIS_ADDR=localhost:6379 \
WORKER_COUNT=10 \
API_KEY=my-secret-key \
CORS_ORIGINS=http://localhost:3000,https://myapp.com \
go run main.gocd dashboard
npm install
npm run devOpens at http://localhost:3000 β real-time visualization of task flow, worker map, and DLQ management. Connects to the API via SSE.
| Endpoint | Description |
|---|---|
http://localhost:2112/metrics |
Raw Prometheus metrics |
http://localhost:8080/api/stream |
SSE stream of real-time task events |
http://localhost:8080/api/workers |
JSON snapshot of current worker status |
http://localhost:8080/api/health |
Health check (Redis connectivity + uptime) |
http://localhost:9090 |
Prometheus UI |
http://localhost:3000 |
Grafana |
http://localhost:3000 |
Dashboard (if running) |
All configuration is via environment variables:
| Variable | Default | Description |
|---|---|---|
REDIS_ADDR |
localhost:6379 |
Redis server address |
REDIS_CLUSTER |
false |
Enable Redis Cluster mode |
REDIS_ADDRS |
localhost:6379 |
Comma-separated cluster node addresses |
STREAM_NAME |
Forge_tasks |
Main task stream name |
GROUP_NAME |
Forge_workers |
Consumer group name |
CONSUMER_NAME |
worker_node_1 |
This consumer's identity |
WORKER_COUNT |
5 |
Number of worker goroutines |
FETCH_BATCH_SIZE |
10 |
Messages per XREADGROUP call |
BLOCK_TIMEOUT |
2s |
XREADGROUP blocking duration |
API_PORT |
:8080 |
HTTP API server port |
METRICS_PORT |
:2112 |
Prometheus metrics port |
CORS_ORIGINS |
http://localhost:3000 |
Comma-separated allowed origins |
API_KEY |
(empty) | Bearer token for DLQ replay (empty = no auth) |
MOCK_TASK_INTERVAL |
2s |
Interval for mock task production |
MAX_RETRIES |
3 |
Default max retries per task |
ENABLE_MOCK_TASKS |
true |
Enable/disable mock task production |
ENABLE_PRIORITY |
false |
Enable priority queue routing |
DLQ_STREAM_NAME |
Forge_tasks_dlq |
Dead-Letter Queue stream name |
Server-Sent Events stream. Emits a JSON event for every task state change.
data: {"type":"Pending","task_id":"task-1","worker_id":""}
data: {"type":"Processing","task_id":"task-1","worker_id":"worker_node_1-3"}
data: {"type":"Completed","task_id":"task-1","worker_id":"worker_node_1-3"}
Event types: Pending Β· Processing Β· Completed Β· Failed Β· DLQ
Returns a JSON array of current worker nodes with CPU and memory stats.
Returns health status and uptime.
{
"status": "healthy",
"uptime": "2h34m12s",
"redis": true
}Moves all tasks in the DLQ back to the main stream with retries reset to zero. Requires Authorization: Bearer <API_KEY> header when API_KEY is set.
{ "success": true, "retried": 4 }Deep-dive guides covering every concept in the project:
| Guide | What You'll Learn |
|---|---|
| Architecture | Every component, data flow, and design decision explained |
| Redis Streams | Complete mental model of XADD, XREADGROUP, XACK, PEL, and consumer groups |
| Concurrency Patterns | Worker pools, channels, WaitGroups, context cancellation, and the shutdown dance |
| Reliability Patterns | DLQ, retry strategies, at-least-once delivery, and data loss prevention |
| Building from Scratch | Step-by-step thinking process to build a task queue from zero |
| Thinking Like an Engineer | Debugging strategies, mental models, code reading, and career growth |
| Explaining to Anyone | How to communicate technical concepts to any audience |
| Observability | Prometheus, PromQL, Grafana dashboards, SSE, and structured logging |
- Task Timeouts β Per-task timeout via
context.WithTimeout - Priority Queues β High/normal/low priority stream routing
- Idempotency Keys β Duplicate prevention with Redis SET NX
- Redis Cluster Support β Horizontal scaling with cluster mode
- Cron / Delayed Jobs β Schedule tasks for future execution or on a recurring interval
- Web Dashboard Auth β Add authentication to the Next.js dashboard
The Next.js dashboard provides real-time visualization:
- Task Columns β Pending, Processing, and DLQ tasks with animated transitions
- Worker Map β Interactive React Flow visualization with pulse effects on activity
- Throughput Stats β Live TPS and P99 latency from benchmark data
- DLQ Management β "Retry All" button to replay failed tasks
- Auto-Reconnect β SSE connection automatically retries on disconnect (up to 5 times)
| Feature | Implementation |
|---|---|
| Memory-safe | Tasks capped at 100 (FIFO eviction) |
| Typed | Full TypeScript β no any types |
| Configurable URL | NEXT_PUBLIC_API_URL env var |
| Loading states | "Connecting..." indicator on startup |
| Error handling | "Connection lost" message with retry |
Please see CONTRIBUTING.md for details on setting up your environment, making changes, and submitting a pull request.
# Unit tests
go test ./...
# Integration tests (requires Redis)
go test -v ./tests/
# Benchmarks
go test -v -run=^$ -bench=BenchmarkForgeQueue -benchtime=1x ./benchmarks/
# Lint
golangci-lint run# Build
docker build -t Forge .
# Run with docker-compose (includes Redis, Prometheus, Grafana)
docker-compose up -d