Documentation Index
Fetch the complete documentation index at: https://mnah05-boiler-go-21-79.mintlify.app/llms.txt
Use this file to discover all available pages before exploring further.
Prerequisites
Before you begin, ensure you have the following installed:
The project uses Docker Compose to run PostgreSQL and Redis, so you don’t need to install them separately.
Installation
Clone the repository
git clone https://github.com/mnah05/boiler-go.git
cd boiler-go
Set up environment variables
Copy the example environment file and configure it:The default configuration works out of the box for local development:# ---------- server ----------
APP_PORT=8080
# ---------- database ----------
DATABASE_URL=postgres://postgres:postgres@localhost:5432/appdb?sslmode=disable
# ---------- redis / asynq ----------
REDIS_ADDR=localhost:6379
REDIS_PASSWORD=
REDIS_DB=0
# ---------- timeouts ----------
HEALTH_CHECK_TIMEOUT=2s
API_SHUTDOWN_TIMEOUT=10s
WORKER_SHUTDOWN_TIMEOUT=30s
# ---------- logging ----------
# Log output destination: stdout | file | both
LOG_OUTPUT=stdout
# Log file path (required when LOG_OUTPUT is "file" or "both")
LOG_FILE=
Start infrastructure services
Launch PostgreSQL and Redis using Docker Compose:This command starts the following services:
- PostgreSQL 16 on port
5432
- Redis 7 on port
6379
Use make dev-down to stop all services when you’re done
Run database migrations
This sets up your database schema using golang-migrate.
Running the application
Boiler-Go consists of two separate processes that work together:
Start the API server
In your first terminal, start the HTTP API server:
You should see output similar to this:
2024-03-03 10:15:32 INF database connected
2024-03-03 10:15:32 INF redis connected
2024-03-03 10:15:32 INF scheduler client initialized
2024-03-03 10:15:32 INF server starting port=8080
The API server is now running on http://localhost:8080.
Start the background worker
In a second terminal, start the background worker process:
You should see output similar to this:
2024-03-03 10:16:45 INF database connected
2024-03-03 10:16:45 INF worker starting
The worker is now processing tasks from the Redis queue.
Test your setup
Check health status
Verify that all services are running correctly:curl http://localhost:8080/health
You should receive a response like this:{
"status": {
"database": "up",
"redis": "up"
},
"checked": "2024-03-03T10:17:23Z",
"duration": 12
}
The duration field shows how long the health check took in milliseconds. Check worker status
Verify that the scheduler is connected:curl http://localhost:8080/worker/status
Response:{
"scheduler": "connected",
"queues": ["critical", "default", "low"],
"note": "Use POST /worker/ping to test task processing"
}
Test worker task processing
Send a ping task to verify end-to-end functionality:curl -X POST http://localhost:8080/worker/ping \
-H "Content-Type: application/json" \
-H "X-Request-ID: test-123" \
-d '{"message": "Hello from API"}'
API response:{
"success": true,
"task_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"task_type": "worker:ping",
"queued_at": "2024-03-03T10:18:00Z",
"message": "Task queued successfully. Check worker logs to verify processing."
}
Check your worker terminal to see the task being processed:2024-03-03 10:18:00 INF task started task_id=a1b2c3d4-e5f6-7890-abcd-ef1234567890 task_type=worker:ping
2024-03-03 10:18:00 INF worker ping task processed - worker is alive! payload="Hello from API" request_id=test-123 task_type=worker:ping
2024-03-03 10:18:00 INF task completed duration=2ms task_id=a1b2c3d4-e5f6-7890-abcd-ef1234567890 task_type=worker:ping
Notice how the request_id is propagated from the API to the worker logs. This enables end-to-end request tracing.
Project structure overview
Here’s what you just set up:
boiler-go/
├── cmd/
│ ├── api/ # HTTP API server entry point
│ └── worker/ # Background job processor entry point
├── internal/
│ ├── config/ # Environment configuration
│ ├── db/ # Database connection pool
│ ├── handler/ # HTTP request handlers
│ ├── middleware/ # HTTP middleware (logging, CORS)
│ ├── queue/ # Queue names and priorities
│ ├── scheduler/ # Job scheduling client
│ └── tasks/ # Task type constants
├── pkg/
│ └── logger/ # Structured logging utilities
├── migrations/ # Database migration files
├── Makefile # Development commands
├── docker-compose.yml # Local infrastructure
└── .env # Configuration
Common development commands
Here are the most frequently used commands:
# Start infrastructure (PostgreSQL + Redis)
make dev
# Stop infrastructure
make dev-down
# Run API server
make api
# Run background worker
make worker
Understanding the code
Let’s look at the API server entry point to understand how everything connects:
func main() {
// Load config first with basic logger
cfg := config.Load(logger.New())
// Create logger based on configuration
logg := newLogger(cfg, "logs/api.log")
ctx := context.Background()
// Initialize database pool with timeout context
dbCtx, dbCancel := context.WithTimeout(ctx, 10*time.Second)
defer dbCancel()
if err := db.Open(dbCtx, cfg); err != nil {
logg.Fatal().Err(err).Msg("failed to initialize database")
}
logg.Info().Msg("database connected")
defer db.Close()
// Initialize Redis client
rdb := redis.NewClient(&redis.Options{
Addr: cfg.RedisAddr,
Password: cfg.RedisPassword,
DB: cfg.RedisDB,
})
// Initialize scheduler client for worker task enqueueing
schedulerClient := scheduler.NewClient(asynq.RedisClientOpt{
Addr: cfg.RedisAddr,
Password: cfg.RedisPassword,
DB: cfg.RedisDB,
})
defer schedulerClient.Close()
// Create router with all dependencies
router := handler.NewRouter(logg, cfg, db.Get(), rdb, schedulerClient)
// Configure HTTP server
server := &http.Server{
Addr: ":" + cfg.AppPort,
Handler: router,
ReadTimeout: 10 * time.Second,
WriteTimeout: 10 * time.Second,
IdleTimeout: 60 * time.Second,
MaxHeaderBytes: 1 << 20, // 1MB
}
// ... graceful shutdown handling
}
Notice the context-aware initialization pattern. The database connection uses a timeout context to prevent hanging during startup.
Next steps
Now that you have a running backend, explore these topics:
Architecture
Learn about the project structure and design patterns
Configuration
Customize timeouts, logging, and other settings
API reference
Explore all available endpoints
Add handlers
Create your first custom endpoint