A multi-tenant distributed job execution platform with explicit control plane / data plane separation.
jobplane allows teams to define background jobs, enqueue executions, and run them in isolated environments through a pluggable runtime layer. It mirrors real-world platform infrastructure with production-grade execution semantics.
┌─────────────────────────────────────────────────────────────────┐
│ Control Plane │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ HTTP API │───▶│ Job Store │───▶│ Queue │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ ▲ │ │
│ │ ▼ │
│ ┌─────┴─────┐ ┌─────────────┐ │
│ │ CLI │ │ PostgreSQL │ │
│ └───────────┘ └──────┬──────┘ │
└───────────────────────────────────────────────┼─────────────────┘
│
┌───────────────────────────────────────────────┼─────────────────┐
│ Data Plane │ │
│ ▼ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Worker │───▶│ Runtime │───▶│ Kubernetes │ │
│ │ Agent │ │ Interface │ │ Docker/Exec │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
└─────────────────────────────────────────────────────────────────┘
- Multi-Tenant – Every operation scoped by
tenant_id - Pluggable Runtimes – Supports Kubernetes Jobs, Docker containers, and raw processes
- Scheduled Execution – Schedule jobs to run at a specific future time (RFC3339)
- Priority Queues – Prioritize critical workloads (Critical, High, Normal, Low)
- Dead Letter Queue (DLQ) – Automatic handling and inspection of permanently failed jobs
- Postgres-Backed Queue –
SELECT FOR UPDATE SKIP LOCKEDfor reliable, transactional job claiming - Graceful Shutdown – SIGTERM handling with in-flight execution completion
- Log Streaming – Real-time log streaming from workers to controller
- Timeout Enforcement – Hard deadlines via
context.WithTimeout - Heartbeat-Based Visibility – Long-running jobs extend queue visibility to prevent duplicate pickup
jobplane/
├── cmd/
│ ├── controller/ # HTTP API server ("Brain")
│ ├── worker/ # Job executor agent ("Muscle")
│ └── cli/ # Developer terminal tool
├── internal/
│ ├── config/ # Environment configuration
│ ├── store/ # Database layer + queue
│ ├── worker/ # Agent logic + runtime interface
│ ├── controller/ # HTTP handlers + middleware
│ └── logger/ # Structured logging (slog)
└── pkg/api/ # Shared request/response types
- Go 1.25+
- PostgreSQL 16+
- Docker (optional, for container runtime)
make build-all# Start PostgreSQL
docker run -d --name jobplane-db \
-e POSTGRES_PASSWORD=secret \
-e POSTGRES_DB=jobplane \
-p 5432:5432 postgres:16
# Run controller
DATABASE_URL="postgres://postgres:secret@localhost:5432/jobplane?sslmode=disable" \
./bin/controller
# Run worker (in another terminal)
DATABASE_URL="postgres://postgres:secret@localhost:5432/jobplane?sslmode=disable" \
./bin/worker./bin/jobctl submit --name "hello" --image "alpine:latest" --command "echo", "Hello, jobplane!"./bin/jobctl submit --name "urgent" --image "alpine:latest" --command "echo", "Fast!" --priority 100# First create the job
./bin/jobctl create --name "nightly" --image "alpine" --command "echo", "nightly run"
# Then run it with a schedule
./bin/jobctl run <job-id> --schedule "2024-12-31T23:59:00Z"./bin/jobctl dlq list
./bin/jobctl dlq retry <execution-id>| Principle | Implementation |
|---|---|
| Control plane is stateless | No in-memory job state; PostgreSQL owns all |
| Data plane executes jobs | Workers pull from queue, controller never runs jobs |
| PostgreSQL as system of record | Transactional queue with visibility semantics |
| At-least-once delivery | Jobs may run multiple times; design for idempotency |
| Multi-tenancy | All queries scoped by tenant_id |
# Run tests
make test
# Lint
make lint
# Format
go fmt ./...MIT