A robust and scalable distributed task scheduling system built with Go. This project demonstrates a modern backend architecture using a REST API, a Redis-based message queue, and a PostgreSQL database for persistent storage and audit logging.
It is designed for high performance and resilience, capable of processing background jobs, scheduling future tasks, and automatically retrying failed executions with exponential backoff.
This system follows a modern, distributed architecture designed for decoupling and scalability:
-
API Layer:
- REST API (on port
8080): Serves as the primary interface for external clients like the CLI and potential web UIs. It uses standard JSON for broad compatibility. - gRPC API (on port
9090): Included as an additional feature to demonstrate a dual-API architecture. It provides a high-performance, strongly-typed interface suitable for internal service-to-service communication. Note: The current CLI client interacts exclusively with the REST API.
- REST API (on port
-
Message Queue:
- Redis acts as a lightweight, fast message broker. Tasks are enqueued here before being picked up by workers, decoupling the API from the processing logic.
-
Worker Pool:
- A pool of concurrent Go routines (workers) constantly polls the Redis queue for new tasks. This allows for parallel processing of jobs.
-
Persistent Storage:
- PostgreSQL serves as the durable data store for:
tasks: The final state of every processed task.task_executions: A detailed audit log of every single attempt to run a task.users: User credentials for API authentication.workers: A registry of active and stale workers.
- PostgreSQL serves as the durable data store for:
-
Command-Line Interface (CLI):
- A dedicated client application (
task-cli) that interacts with the REST API to create, manage, and inspect tasks.
- A dedicated client application (
- Asynchronous Task Processing: Offload long-running jobs from the main request-response cycle.
- Scheduled Tasks: Ability to schedule tasks for future execution.
- Job Retries: Automatic retries with exponential backoff for failed tasks.
- Priority Queues: Process high-priority tasks before lower-priority ones.
- Dual API Support: Flexible interaction via REST (JSON) and an optional gRPC (Protobuf) interface for advanced use cases.
- Authentication: Secure endpoints using JWT-based session management.
- Concurrent Worker Pool: Efficiently process multiple tasks in parallel.
- Detailed Auditing: Full history of every task attempt is stored in the database.
- Graceful Shutdown: Workers and servers shut down cleanly, finishing in-progress work where possible.
- Go (version 1.22 or later)
- PostgreSQL (version 14 or later)
- Redis (version 7 or later)
- migrate CLI tool
- grpcurl (for testing the gRPC API)
-
Clone the repository:
git clone https://github.com/your-username/task-scheduler.git cd task-scheduler -
Start Database and Cache Services: Ensure you have instances of PostgreSQL and Redis running and accessible. You can install them locally or use a cloud provider.
-
Run Database Migrations: Create the necessary tables and schemas in your PostgreSQL database.
# Example command, update with your database connection details migrate -path internal/database/migrations -database "postgres://user:password@localhost:5432/tasksdb?sslmode=disable" up -
Configure Environment Variables: Copy the example environment file and update it with your database and Redis connection details.
cp .env.example .env # Open .env and edit the variables -
Install Go Dependencies: Navigate to the backend and CLI directories to install dependencies.
# Backend cd backend go mod tidy # CLI cd ../cli go mod tidy
From the backend directory, run the main application. This will start both the REST and gRPC servers.
cd backend
go run ./cmd/scheduler
You should see logs indicating that the servers have started on ports 8080 (HTTP) and 9090 (gRPC).
You can use curl or Postman to interact with the REST API.
Example: Create a Task
# Note: Most endpoints require authentication.
curl -X POST http://localhost:8080/api/v1/tasks \
-H "Content-Type: application/json" \
-d '{
"name": "Process Daily Report",
"type": "report_generation",
"payload": { "report_id": "xyz-123" }
}'
First, build the CLI executable.
cd cli
go build -o task-cli .
Then, use the task-cli command to interact with the server's REST API.
# Get help
./task-cli --help
# Create a new task
./task-cli task create --name "My CLI Task" --type "cli_test" --payload '{"source":"cli"}'
# List tasks
./task-cli task list
.
├── backend/ # Main backend application source
│ ├── cmd/scheduler/ # Main entry point (main.go)
│ ├── internal/ # All internal application logic
│ │ ├── auth/ # Authentication (JWT)
│ │ ├── cache/ # Redis caching logic
│ │ ├── config/ # Configuration loading
│ │ ├── cron/ # Cron job scheduling
│ │ ├── database/ # Database connection
│ │ ├── executor/ # Task execution logic
│ │ ├── grpc/ # gRPC server implementation
│ │ ├── handlers/ # HTTP handlers
│ │ ├── middlewares/ # Middlewares
│ │ ├── models/ # Database model structs
│ │ ├── queue/ # Redis queue implementation
│ │ └── repository/ # Database interaction layer
│ └── go.mod
├── cli/ # CLI client application
│ ├── client/ # REST API client for the CLI
│ └── cmd/ # Cobra command definitions
├── migrations/ # SQL database migration files
├── proto/ # Protocol Buffer definitions (.proto)
├── scripts/ # Helper scripts (e.g., for generating code)
├── .env.example # Example environment variables
└── README.md