docs: document daemon process management commands
Update README.md and CLAUDE.md to document new process management: - Add "Process Management" section with daemon commands - Update all examples to use `./kvs start/stop/status` instead of `&` and `pkill` - Document global PID/log directories (~/.kvs/) - Update cluster setup examples - Update development workflow - Add daemon package to project structure 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
76
CLAUDE.md
76
CLAUDE.md
@@ -10,10 +10,16 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
|
|||||||
go build -o kvs .
|
go build -o kvs .
|
||||||
|
|
||||||
# Run with default config (auto-generates config.yaml)
|
# Run with default config (auto-generates config.yaml)
|
||||||
./kvs
|
./kvs start config.yaml
|
||||||
|
|
||||||
# Run with custom config
|
# 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
|
# Run comprehensive integration tests
|
||||||
./integration_test.sh
|
./integration_test.sh
|
||||||
@@ -25,6 +31,32 @@ go run test_conflict.go data1 data2
|
|||||||
go build -o kvs . && ./integration_test.sh
|
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
|
### Development Workflow
|
||||||
```bash
|
```bash
|
||||||
# Format and check code
|
# Format and check code
|
||||||
@@ -38,11 +70,25 @@ go mod tidy
|
|||||||
go build .
|
go build .
|
||||||
|
|
||||||
# Test specific cluster scenarios
|
# Test specific cluster scenarios
|
||||||
./kvs node1.yaml & # Terminal 1
|
./kvs start node1.yaml
|
||||||
./kvs node2.yaml & # Terminal 2
|
./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 -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
|
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
|
## Architecture Overview
|
||||||
@@ -58,7 +104,8 @@ KVS is a **distributed, eventually consistent key-value store** built around thr
|
|||||||
|
|
||||||
#### Modular Package Design
|
#### Modular Package Design
|
||||||
- **`auth/`** - Complete JWT authentication system with POSIX-inspired permissions
|
- **`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
|
- **`storage/`** - BadgerDB abstraction with compression and revision history
|
||||||
- **`server/`** - HTTP handlers, routing, and lifecycle management
|
- **`server/`** - HTTP handlers, routing, and lifecycle management
|
||||||
- **`features/`** - Utility functions for TTL, rate limiting, tamper logging, backup
|
- **`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
|
- **Bootstrap sync**: Up to 30 days of historical data for new nodes
|
||||||
|
|
||||||
#### Main Entry Point Flow
|
#### Main Entry Point Flow
|
||||||
1. `main.go` loads config (auto-generates default if missing)
|
1. `main.go` parses command-line arguments for subcommands (`start`, `stop`, `status`, `restart`)
|
||||||
2. `server.NewServer()` initializes all subsystems
|
2. For daemon mode: `daemon.Daemonize()` spawns background process and manages PID files
|
||||||
3. Graceful shutdown handling with `SIGINT`/`SIGTERM`
|
3. For server mode: loads config (auto-generates default if missing)
|
||||||
4. All business logic delegated to modular packages
|
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.
|
This architecture enables easy feature addition, comprehensive testing, and reliable operation in distributed environments while maintaining simplicity for single-node deployments.
|
115
README.md
115
README.md
@@ -69,11 +69,67 @@ go build -o kvs .
|
|||||||
|
|
||||||
### Quick Test
|
### Quick Test
|
||||||
```bash
|
```bash
|
||||||
# Start standalone node
|
# Start standalone node (uses config.yaml if it exists, or creates it)
|
||||||
./kvs
|
./kvs start config.yaml
|
||||||
|
|
||||||
# Test the API
|
# Test the API
|
||||||
curl http://localhost:8080/health
|
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
|
## ⚙️ Configuration
|
||||||
@@ -308,17 +364,23 @@ clustering_enabled: true
|
|||||||
|
|
||||||
#### Start the Cluster
|
#### Start the Cluster
|
||||||
```bash
|
```bash
|
||||||
# Terminal 1
|
# Start as daemons
|
||||||
./kvs node1.yaml
|
./kvs start node1.yaml
|
||||||
|
sleep 2
|
||||||
# Terminal 2 (wait a few seconds)
|
./kvs start node2.yaml
|
||||||
./kvs node2.yaml
|
sleep 2
|
||||||
|
./kvs start node3.yaml
|
||||||
# Terminal 3 (wait a few seconds)
|
|
||||||
./kvs node3.yaml
|
|
||||||
|
|
||||||
# Verify cluster formation
|
# Verify cluster formation
|
||||||
curl http://localhost:8081/members/ # Should show all 3 nodes
|
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
|
## 🔄 How It Works
|
||||||
@@ -364,9 +426,10 @@ go build -o kvs .
|
|||||||
./integration_test.sh
|
./integration_test.sh
|
||||||
|
|
||||||
# Manual basic functionality test
|
# Manual basic functionality test
|
||||||
./kvs &
|
./kvs start config.yaml
|
||||||
|
sleep 2
|
||||||
curl http://localhost:8080/health
|
curl http://localhost:8080/health
|
||||||
pkill kvs
|
./kvs stop config
|
||||||
|
|
||||||
# Manual cluster test (requires creating configs)
|
# Manual cluster test (requires creating configs)
|
||||||
echo 'node_id: "test1"
|
echo 'node_id: "test1"
|
||||||
@@ -379,8 +442,9 @@ port: 8082
|
|||||||
seed_nodes: ["127.0.0.1:8081"]
|
seed_nodes: ["127.0.0.1:8081"]
|
||||||
auth_enabled: false' > test2.yaml
|
auth_enabled: false' > test2.yaml
|
||||||
|
|
||||||
./kvs test1.yaml &
|
./kvs start test1.yaml
|
||||||
./kvs test2.yaml &
|
sleep 2
|
||||||
|
./kvs start test2.yaml
|
||||||
|
|
||||||
# Test data replication (wait for cluster formation)
|
# Test data replication (wait for cluster formation)
|
||||||
sleep 10
|
sleep 10
|
||||||
@@ -393,7 +457,8 @@ sleep 30
|
|||||||
curl http://localhost:8082/kv/test/data
|
curl http://localhost:8082/kv/test/data
|
||||||
|
|
||||||
# Cleanup
|
# Cleanup
|
||||||
pkill kvs
|
./kvs stop test1
|
||||||
|
./kvs stop test2
|
||||||
rm test1.yaml test2.yaml
|
rm test1.yaml test2.yaml
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -418,17 +483,22 @@ auth_enabled: false
|
|||||||
log_level: "debug"' > conflict2.yaml
|
log_level: "debug"' > conflict2.yaml
|
||||||
|
|
||||||
# Start nodes with conflicting data
|
# Start nodes with conflicting data
|
||||||
./kvs conflict1.yaml &
|
./kvs start conflict1.yaml
|
||||||
./kvs conflict2.yaml &
|
sleep 2
|
||||||
|
./kvs start conflict2.yaml
|
||||||
|
|
||||||
# Watch logs for conflict resolution
|
# 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
|
# Both nodes will converge within ~10-30 seconds
|
||||||
# Check final state
|
# Check final state
|
||||||
sleep 30
|
sleep 30
|
||||||
curl http://localhost:9111/kv/test/conflict/data
|
curl http://localhost:9111/kv/test/conflict/data
|
||||||
curl http://localhost:9112/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
|
rm conflict1.yaml conflict2.yaml
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -474,6 +544,10 @@ kvs/
|
|||||||
├── config/ # Configuration management
|
├── config/ # Configuration management
|
||||||
│ └── config.go # Config loading & defaults
|
│ └── config.go # Config loading & defaults
|
||||||
│
|
│
|
||||||
|
├── daemon/ # Process management
|
||||||
|
│ ├── daemonize.go # Background process spawning
|
||||||
|
│ └── pid.go # PID file management
|
||||||
|
│
|
||||||
├── features/ # Utility features
|
├── features/ # Utility features
|
||||||
│ ├── auth.go # Auth utilities
|
│ ├── auth.go # Auth utilities
|
||||||
│ ├── backup.go # Backup system
|
│ ├── backup.go # Backup system
|
||||||
@@ -580,8 +654,9 @@ type StoredValue struct {
|
|||||||
## 🛡️ Production Considerations
|
## 🛡️ Production Considerations
|
||||||
|
|
||||||
### Deployment
|
### Deployment
|
||||||
- Use systemd or similar for process management
|
- Built-in daemon commands (`start`/`stop`/`restart`/`status`) for process management
|
||||||
- Configure log rotation for JSON logs
|
- Alternatively, use systemd or similar for advanced orchestration
|
||||||
|
- Logs automatically written to `~/.kvs/logs/` (configure log rotation)
|
||||||
- Set up monitoring for `/health` endpoint
|
- Set up monitoring for `/health` endpoint
|
||||||
- Use reverse proxy (nginx/traefik) for TLS and load balancing
|
- Use reverse proxy (nginx/traefik) for TLS and load balancing
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user