self-daemonize #16

Open
ryyst wants to merge 6 commits from self-daemonize into master
2 changed files with 161 additions and 30 deletions
Showing only changes of commit 64680a6ece - Show all commits

View File

@@ -10,10 +10,16 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
go build -o kvs .
# Run with default config (auto-generates config.yaml)
./kvs
./kvs start config.yaml
# Run with custom config
./kvs /path/to/config.yaml
./kvs start /path/to/config.yaml
# Check running instances
./kvs status
# Stop instance
./kvs stop config
# Run comprehensive integration tests
./integration_test.sh
@@ -25,6 +31,32 @@ go run test_conflict.go data1 data2
go build -o kvs . && ./integration_test.sh
```
### Process Management Commands
```bash
# Start as background daemon
./kvs start <config.yaml> # .yaml extension optional
# Stop daemon
./kvs stop <config> # Graceful SIGTERM shutdown
# Restart daemon
./kvs restart <config> # Stop then start
# Show status
./kvs status # All instances
./kvs status <config> # Specific instance
# Run in foreground (for debugging)
./kvs <config.yaml> # Logs to stdout, blocks terminal
# View daemon logs
tail -f ~/.kvs/logs/kvs_<config>.yaml.log
# Global state directories
~/.kvs/pids/ # PID files (works from any directory)
~/.kvs/logs/ # Daemon log files
```
### Development Workflow
```bash
# Format and check code
@@ -38,11 +70,25 @@ go mod tidy
go build .
# Test specific cluster scenarios
./kvs node1.yaml & # Terminal 1
./kvs node2.yaml & # Terminal 2
./kvs start node1.yaml
./kvs start node2.yaml
# Wait for cluster formation
sleep 5
# Test data operations
curl -X PUT http://localhost:8081/kv/test/data -H "Content-Type: application/json" -d '{"test":"data"}'
curl http://localhost:8082/kv/test/data # Should replicate within ~30 seconds
pkill kvs
# Check daemon status
./kvs status
# View logs
tail -f ~/.kvs/logs/kvs_node1.yaml.log
# Cleanup
./kvs stop node1
./kvs stop node2
```
## Architecture Overview
@@ -58,7 +104,8 @@ KVS is a **distributed, eventually consistent key-value store** built around thr
#### Modular Package Design
- **`auth/`** - Complete JWT authentication system with POSIX-inspired permissions
- **`cluster/`** - Distributed systems logic (gossip, sync, merkle trees)
- **`cluster/`** - Distributed systems logic (gossip, sync, merkle trees)
- **`daemon/`** - Process management (daemonization, PID files, lifecycle)
- **`storage/`** - BadgerDB abstraction with compression and revision history
- **`server/`** - HTTP handlers, routing, and lifecycle management
- **`features/`** - Utility functions for TTL, rate limiting, tamper logging, backup
@@ -147,9 +194,18 @@ Creates two BadgerDB instances with intentionally conflicting data (same path, s
- **Bootstrap sync**: Up to 30 days of historical data for new nodes
#### Main Entry Point Flow
1. `main.go` loads config (auto-generates default if missing)
2. `server.NewServer()` initializes all subsystems
3. Graceful shutdown handling with `SIGINT`/`SIGTERM`
4. All business logic delegated to modular packages
1. `main.go` parses command-line arguments for subcommands (`start`, `stop`, `status`, `restart`)
2. For daemon mode: `daemon.Daemonize()` spawns background process and manages PID files
3. For server mode: loads config (auto-generates default if missing)
4. `server.NewServer()` initializes all subsystems
5. Graceful shutdown handling with `SIGINT`/`SIGTERM`
6. All business logic delegated to modular packages
#### Daemon Architecture
- **PID Management**: Global PID files stored in `~/.kvs/pids/` for cross-directory access
- **Logging**: Daemon logs written to `~/.kvs/logs/{config-name}.log`
- **Process Lifecycle**: Spawns detached process via `exec.Command()` with `Setsid: true`
- **Config Normalization**: Supports both `node1` and `node1.yaml` formats
- **Stale PID Detection**: Checks process existence via `Signal(0)` before operations
This architecture enables easy feature addition, comprehensive testing, and reliable operation in distributed environments while maintaining simplicity for single-node deployments.

115
README.md
View File

@@ -69,11 +69,67 @@ go build -o kvs .
### Quick Test
```bash
# Start standalone node
./kvs
# Start standalone node (uses config.yaml if it exists, or creates it)
./kvs start config.yaml
# Test the API
curl http://localhost:8080/health
# Check status
./kvs status
# Stop when done
./kvs stop config
```
## 🎮 Process Management
KVS includes systemd-style daemon commands for easy process management:
```bash
# Start as background daemon
./kvs start config.yaml # or just: ./kvs start config
./kvs start node1.yaml # Start with custom config
# Check status
./kvs status # Show all running instances
./kvs status node1 # Show specific instance
# Stop daemon
./kvs stop node1 # Graceful shutdown
# Restart daemon
./kvs restart node1 # Stop and start
# Run in foreground (traditional)
./kvs node1.yaml # Logs to stdout
```
### Daemon Features
- **Global PID tracking**: PID files stored in `~/.kvs/pids/` (works from any directory)
- **Automatic logging**: Logs written to `~/.kvs/logs/{config-name}.log`
- **Flexible naming**: Config extension optional (`node1` or `node1.yaml` both work)
- **Graceful shutdown**: SIGTERM sent for clean shutdown
- **Stale PID cleanup**: Automatically detects and cleans dead processes
- **Multi-instance**: Run multiple KVS instances on same machine
### Example Workflow
```bash
# Start 3-node cluster as daemons
./kvs start node1.yaml
./kvs start node2.yaml
./kvs start node3.yaml
# Check cluster status
./kvs status
# View logs
tail -f ~/.kvs/logs/kvs_node1.yaml.log
# Stop entire cluster
./kvs stop node1
./kvs stop node2
./kvs stop node3
```
## ⚙️ Configuration
@@ -308,17 +364,23 @@ clustering_enabled: true
#### Start the Cluster
```bash
# Terminal 1
./kvs node1.yaml
# Terminal 2 (wait a few seconds)
./kvs node2.yaml
# Terminal 3 (wait a few seconds)
./kvs node3.yaml
# Start as daemons
./kvs start node1.yaml
sleep 2
./kvs start node2.yaml
sleep 2
./kvs start node3.yaml
# Verify cluster formation
curl http://localhost:8081/members/ # Should show all 3 nodes
# Check daemon status
./kvs status
# Stop cluster when done
./kvs stop node1
./kvs stop node2
./kvs stop node3
```
## 🔄 How It Works
@@ -364,9 +426,10 @@ go build -o kvs .
./integration_test.sh
# Manual basic functionality test
./kvs &
./kvs start config.yaml
sleep 2
curl http://localhost:8080/health
pkill kvs
./kvs stop config
# Manual cluster test (requires creating configs)
echo 'node_id: "test1"
@@ -379,8 +442,9 @@ port: 8082
seed_nodes: ["127.0.0.1:8081"]
auth_enabled: false' > test2.yaml
./kvs test1.yaml &
./kvs test2.yaml &
./kvs start test1.yaml
sleep 2
./kvs start test2.yaml
# Test data replication (wait for cluster formation)
sleep 10
@@ -393,7 +457,8 @@ sleep 30
curl http://localhost:8082/kv/test/data
# Cleanup
pkill kvs
./kvs stop test1
./kvs stop test2
rm test1.yaml test2.yaml
```
@@ -418,17 +483,22 @@ auth_enabled: false
log_level: "debug"' > conflict2.yaml
# Start nodes with conflicting data
./kvs conflict1.yaml &
./kvs conflict2.yaml &
./kvs start conflict1.yaml
sleep 2
./kvs start conflict2.yaml
# Watch logs for conflict resolution
tail -f ~/.kvs/logs/kvs_conflict1.yaml.log ~/.kvs/logs/kvs_conflict2.yaml.log &
# Both nodes will converge within ~10-30 seconds
# Check final state
sleep 30
curl http://localhost:9111/kv/test/conflict/data
curl http://localhost:9112/kv/test/conflict/data
pkill kvs
# Cleanup
./kvs stop conflict1
./kvs stop conflict2
rm conflict1.yaml conflict2.yaml
```
@@ -474,6 +544,10 @@ kvs/
├── config/ # Configuration management
│ └── config.go # Config loading & defaults
├── daemon/ # Process management
│ ├── daemonize.go # Background process spawning
│ └── pid.go # PID file management
├── features/ # Utility features
│ ├── auth.go # Auth utilities
│ ├── backup.go # Backup system
@@ -580,8 +654,9 @@ type StoredValue struct {
## 🛡️ Production Considerations
### Deployment
- Use systemd or similar for process management
- Configure log rotation for JSON logs
- Built-in daemon commands (`start`/`stop`/`restart`/`status`) for process management
- Alternatively, use systemd or similar for advanced orchestration
- Logs automatically written to `~/.kvs/logs/` (configure log rotation)
- Set up monitoring for `/health` endpoint
- Use reverse proxy (nginx/traefik) for TLS and load balancing