Add daemon health check endpoint (bd-146)
- Add OpHealth RPC operation to protocol - Implement handleHealth() with DB ping and 1s timeout - Returns status (healthy/degraded/unhealthy), uptime, cache metrics - Update TryConnect() to use health check instead of ping - Add 'bd daemon --health' CLI command with JSON output - Track cache hits/misses for metrics - Unhealthy daemon triggers automatic fallback to direct mode - Health check completes in <2 seconds Amp-Thread-ID: https://ampcode.com/threads/T-1a4889f3-77cf-433a-a704-e1c383929f48 Co-authored-by: Amp <amp@ampcode.com>
This commit is contained in:
@@ -17,7 +17,7 @@ type Client struct {
|
||||
}
|
||||
|
||||
// TryConnect attempts to connect to the daemon socket
|
||||
// Returns nil if no daemon is running
|
||||
// Returns nil if no daemon is running or unhealthy
|
||||
func TryConnect(socketPath string) (*Client, error) {
|
||||
if _, err := os.Stat(socketPath); os.IsNotExist(err) {
|
||||
if os.Getenv("BD_DEBUG") != "" {
|
||||
@@ -40,14 +40,28 @@ func TryConnect(socketPath string) (*Client, error) {
|
||||
timeout: 30 * time.Second,
|
||||
}
|
||||
|
||||
if err := client.Ping(); err != nil {
|
||||
health, err := client.Health()
|
||||
if err != nil {
|
||||
if os.Getenv("BD_DEBUG") != "" {
|
||||
fmt.Fprintf(os.Stderr, "Debug: ping failed: %v\n", err)
|
||||
fmt.Fprintf(os.Stderr, "Debug: health check failed: %v\n", err)
|
||||
}
|
||||
conn.Close()
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
if health.Status == "unhealthy" {
|
||||
if os.Getenv("BD_DEBUG") != "" {
|
||||
fmt.Fprintf(os.Stderr, "Debug: daemon unhealthy: %s\n", health.Error)
|
||||
}
|
||||
conn.Close()
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
if os.Getenv("BD_DEBUG") != "" {
|
||||
fmt.Fprintf(os.Stderr, "Debug: connected to daemon (status: %s, uptime: %.1fs, cache: %d)\n",
|
||||
health.Status, health.Uptime, health.CacheSize)
|
||||
}
|
||||
|
||||
return client, nil
|
||||
}
|
||||
|
||||
@@ -131,6 +145,21 @@ func (c *Client) Ping() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Health sends a health check request to verify the daemon is healthy
|
||||
func (c *Client) Health() (*HealthResponse, error) {
|
||||
resp, err := c.Execute(OpHealth, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var health HealthResponse
|
||||
if err := json.Unmarshal(resp.Data, &health); err != nil {
|
||||
return nil, fmt.Errorf("failed to unmarshal health response: %w", err)
|
||||
}
|
||||
|
||||
return &health, nil
|
||||
}
|
||||
|
||||
// Create creates a new issue via the daemon
|
||||
func (c *Client) Create(args *CreateArgs) (*Response, error) {
|
||||
return c.Execute(OpCreate, args)
|
||||
|
||||
Reference in New Issue
Block a user