A distributed task scheduling system built with Go, gRPC, and PostgreSQL that executes HTTP requests at specified times. Features horizontal scalability, fault tolerance, and efficient task distribution.
Schedulo consists of four main components:
- Exposes REST endpoints for task submission and status tracking
- Validates and persists tasks to PostgreSQL
- Handles task scheduling requests with ISO 8601 timestamps
- Stores task metadata with UUID primary keys
- Tracks task lifecycle:
scheduled_at,picked_at,started_at,completed_at,failed_at
- Database Scanning: Polls database every 10 seconds for tasks ready to execute
- Exclusive Row-Level Locking: Uses
SELECT ... FOR UPDATE SKIP LOCKEDto prevent race conditions - Transaction Management: Atomic task assignment with proper commit/rollback handling
- Worker Pool Management:
- Maintains active worker registry with health monitoring
- Implements round-robin load balancing across workers
- Thread-safe worker pool using
sync.Mutexandsync.RWMutex - Removes inactive workers after missing heartbeats
- Heartbeat Protocol: Workers send heartbeats every 5 seconds
- gRPC Server: Receives task submissions from coordinator
- Worker Pool: Configurable number of goroutines (default: 5)
- Task Execution:
- Performs HTTP requests with configurable timeouts (10s)
- Supports bearer token authentication
- Handles JSON payloads
- Status Updates: Reports task lifecycle events to coordinator
- Graceful Shutdown: Uses context cancellation and
sync.WaitGroup
Tasks can invoke any HTTP endpoint (e.g., api.example.com)
- Mutex Protection: All shared state protected with appropriate locks
- Context-Based Cancellation: Graceful shutdown across all goroutines
- WaitGroup Coordination: Ensures all workers complete before shutdown
- Row-Level Locking:
FOR UPDATE SKIP LOCKEDprevents task duplication - Transaction Isolation: ACID compliance for task state transitions
- Indexed Queries:
scheduled_atindex for efficient task scanning
- gRPC: Low-latency binary protocol for inter-service communication
- Protocol Buffers: Efficient serialization with strong typing
- Connection Pooling: Reused connections with PostgreSQL (pgxpool)
- Heartbeat Monitoring: Automatic worker deregistration on failure
- Retry Logic: Database connection retries with exponential backoff
- Graceful Degradation: System continues with reduced worker capacity
- Docker & Docker Compose
- Go 1.25+ (for local development)
- Clone the repository
git clone https://github.com/subediDarshan/schedulo.git
cd schedulo- Configure environment
# Create .env file
cat > .env << EOF
POSTGRES_DB=schedulo
POSTGRES_USER=admin
POSTGRES_PASSWORD=secure_password
EOF- Start the system (with 3 workers)
docker compose up --scale worker=3Services will be available at:
- Scheduler API:
http://localhost:8081 - Coordinator gRPC:
localhost:8080 - PostgreSQL:
localhost:5432
POST http://localhost:8081/schedule
Content-Type: application/json
{
"endpoint": "https://api.example.com/api/task",
"scheduled_at": "2025-10-29T15:30:00Z",
"method": "POST",
"bearer_token": "your-token-here",
"payload": {"key": "value"}
}Response:
{
"task_id": "550e8400-e29b-41d4-a716-446655440000",
"endpoint": "https://api.example.com/api/task",
"scheduled_at": "2025-10-29T15:30:00Z"
}GET http://localhost:8081/status?task_id=550e8400-e29b-41d4-a716-446655440000Response:
{
"task_id": "550e8400-e29b-41d4-a716-446655440000",
"endpoint": "https://api.example.com/api/task",
"scheduled_at": "2025-10-29T15:30:00Z",
"picked_at": "2025-10-29T15:29:55Z",
"started_at": "2025-10-29T15:30:01Z",
"completed_at": "2025-10-29T15:30:02Z"
}# Scale to 5 workers
docker-compose up --scale worker=5 -d
# Scale down to 1 worker
docker-compose up --scale worker=1 -dKey parameters (edit service files):
DefaultHeartbeatInterval: 5 secondsdefaultScanInterval: 10 secondsdefaultMaxHeartbeatMisses: 1workerPoolSize: 5 concurrent task processors- Task execution timeout: 10 seconds
