Self-hosted HTTP proxy for scheduling delayed message delivery. Accepts requests and forwards them after a specified delay (0 seconds to ~68 years).
What: Simple API - target URL in path, delay in header, forwards with original headers/body.
Why: Replaces unreliable third-party SaaS HTTP schedulers
How: Redis sorted sets with timestamp-based job scheduling. At-least-once delivery guarantee.
- Python 3.13 + uv
- FastAPI + uvloop (high-performance HTTP API)
- Redis sorted sets (timestamp-based scheduling)
- Docker
Format: YYYY-MM-DD HH:MM:SS.mmm [LEVEL] EVENT [request_id] key=value ...
| Event | Level | Description |
|---|---|---|
APP_START | INFO | Application starting |
EVENT_LOOP | INFO | Event loop type |
REDIS_CONNECT | INFO | Redis connection established |
WORKER_TASK | INFO | Background worker task created |
WORKER_START | INFO | Worker polling loop started |
| Event | Level | Description |
|---|---|---|
HTTP_ACCESS | INFO | Uvicorn access log |
REQUEST | INFO | Incoming scheduling request |
AUTH_FAIL | WARN | API key validation failed |
BODY_PARSE | WARN | JSON body parsing failed |
ENQUEUE | INFO | Job added to queue |
ENQUEUE_FAIL | ERROR | Failed to add job to queue |
| Event | Level | Description |
|---|---|---|
BATCH_ACQUIRE | INFO | Jobs retrieved from queue |
PROCESS | INFO | Processing a job |
FORWARD | INFO | Starting HTTP forward |
RESPONSE | INFO | HTTP forward completed |
FORWARD_ERROR | ERROR | HTTP forward failed |
BATCH_DONE | INFO | Batch processing complete |
WORKER_ERROR | ERROR | Unexpected worker error |
| Event | Level | Description |
|---|---|---|
REDIS_ZADD | DEBUG | Job added to sorted set |
REDIS_ZRANGEBYSCORE | DEBUG | Jobs queried |
REDIS_ZREMRANGEBYSCORE | DEBUG | Jobs removed |
| Event | Level | Description |
|---|---|---|
REDIS_CLOSE | INFO | Redis connection closed |
SHUTDOWN | INFO | Application shutdown complete |