Run multiple instances of a service and sync all data between all service instances.
- No external database required
- Auto-clustering with Serf gossip protocol
- Automatic data synchronization across all nodes
- Auto failover and failure detection
- Startup synchronization guarantee
- Health check endpoints for monitoring
- Configurable log levels
- Easy to use
- Minimal configuration
This service is a distributed todo list REST API built with Huma, SQLite, and Serf.
go build -o auto-cluster-sync ./cmd/server# Standalone mode (port 8080, database: ./todos.db)
./auto-cluster-sync
# With command line flags
./auto-cluster-sync -port 3000 -db /tmp/todos.db
# With configuration file
./auto-cluster-sync -config configs/local_1.yaml
# Show help
./auto-cluster-sync -hInteractive API documentation is available at:
http://localhost:8080/docs
# Check if node is ready (fully synced)
curl http://localhost:8080/health/readyReturns 200 OK when ready, 503 Service Unavailable when still syncing.
# Get cluster status and member information
curl http://localhost:8080/health/infoReturns detailed information about:
- Node name and ready status
- Cluster mode (enabled/disabled)
- Number of cluster members
- List of all members with their status
- Number of todos in local database
curl http://localhost:8080/todoscurl http://localhost:8080/todos/1curl -X POST http://localhost:8080/todos \
-H "Content-Type: application/json" \
-d '{"extern_id": "unique-id-123", "todo": "Buy groceries"}'# Update text
curl -X PUT http://localhost:8080/todos/1 \
-H "Content-Type: application/json" \
-d '{"todo": "Buy groceries and cook dinner"}'
# Mark as completed
curl -X PUT http://localhost:8080/todos/1 \
-H "Content-Type: application/json" \
-d '{"completed": true}'
# Update both
curl -X PUT http://localhost:8080/todos/1 \
-H "Content-Type: application/json" \
-d '{"todo": "Buy groceries and cook dinner", "completed": true}'curl -X DELETE http://localhost:8080/todos/1Create a YAML config file with the following structure:
# Log level: debug, info, warn, error (default: info)
log_level: "info"
node:
name: "node-1"
serf:
bind_addr: "127.0.0.1:7946"
http:
port: 8080
database:
path: "./todos-node1.db"
cluster:
seeds:
- "127.0.0.1:7946"
join_timeout: 10-config- Path to YAML configuration file-port- HTTP server port (overrides config, default:8080)-db- Database file path (overrides config, default:./todos.db)-node-name- Node name (overrides config)-serf-addr- Serf bind address (overrides config)-keygen- Generate encryption key for Serf cluster and exit
Note: Command line flags take precedence over config file values.
.
├── cmd/
│ └── server/ # Main application entry point
│ └── main.go
├── internal/
│ ├── api/ # HTTP API handlers and routes
│ │ └── api.go
│ ├── cluster/ # Serf cluster management
│ │ ├── cluster.go # Cluster lifecycle and state
│ │ ├── events.go # Event handlers
│ │ ├── sync.go # Broadcasting operations
│ │ ├── queries.go # Full state sync
│ │ └── types.go # Event type definitions
│ ├── config/ # Configuration loading
│ │ └── config.go
│ ├── database/ # Database layer and CRUD operations
│ │ └── database.go
│ └── models/ # Data models
│ └── todo.go
├── configs/ # Example configuration files
│ ├── local_1.yaml
│ ├── local_2.yaml
│ └── local_3.yaml
└── go.mod
The SQLite database contains a single todos table:
| Column | Type | Description |
|---|---|---|
| id | INTEGER | Primary key (auto-increment) |
| extern_id | TEXT | External ID for synchronization (unique) |
| todo | TEXT | Todo description |
| completed | BOOLEAN | Whether the todo is completed |
| created_at | TIMESTAMP | When the todo was created |
The application supports clustering using Hashicorp Serf for service discovery and todo synchronization.
For production deployments, you can enable Serf encryption by generating a secure encryption key:
# Generate a new encryption key
./auto-cluster-sync -keygenThis command generates a cryptographically secure 32-byte (256-bit) encryption key and displays it with usage instructions. Add the generated key to the cluster.encrypt_key field in your configuration file.
Important: All nodes in the cluster must use the same encryption key to communicate securely.
Start multiple nodes using the provided configuration files:
# Terminal 1 - Node 1
./auto-cluster-sync -config configs/local_1.yaml
# Terminal 2 - Node 2
./auto-cluster-sync -config configs/local_2.yaml
# Terminal 3 - Node 3
./auto-cluster-sync -config configs/local_3.yamlEach node will:
- Initialize its local SQLite database
- Join the cluster via seed nodes
- Request full sync from existing nodes
- Wait for sync to complete (max 30s)
- Start HTTP server and accept requests
- Service Discovery: Nodes discover each other via Serf gossip protocol
- Data Sync: Todo CRUD operations are automatically synchronized across all nodes
- Idempotency:
extern_idensures todos are not duplicated across nodes - Full Sync: New nodes automatically request full state from existing nodes
- Startup Guarantee: HTTP server only starts after full sync is complete (max 30s timeout)
- Failure Detection: Failed nodes are automatically detected and removed
- Health Check:
/health/readyendpoint returns 503 until node is fully synced
When you create a todo on any node, it's automatically synced to all other nodes:
# Create on node 1
curl -X POST http://localhost:8080/todos \
-H "Content-Type: application/json" \
-d '{"extern_id": "todo-1", "todo": "Buy milk"}'
# Todo is now available on all nodes:
curl http://localhost:8081/todos # Node 2
curl http://localhost:8082/todos # Node 3- Basic REST API with CRUD operations
- SQLite database integration
- Auto-clustering with service discovery (Serf)
- Data synchronization between instances
- Auto failover support (Serf failure detection)
- Startup synchronization guarantee
- Health check endpoints (
/health/ready,/health/info) - Configurable log levels
- YAML configuration support
- Serf encryption key generation tool
- Metrics and monitoring (Prometheus)
- TLS support for HTTP API