Refactor WaitForHealthy method to use direct health check URL and simplify health check logic

This commit is contained in:
2025-08-20 15:58:08 +02:00
parent 8265a94bf7
commit 1939b45312

View File

@@ -152,37 +152,42 @@ func (i *Process) WaitForHealthy(timeout int) error {
if timeout <= 0 { if timeout <= 0 {
timeout = 30 // Default to 30 seconds if no timeout is specified timeout = 30 // Default to 30 seconds if no timeout is specified
} }
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(timeout)*time.Second) ctx, cancel := context.WithTimeout(context.Background(), time.Duration(timeout)*time.Second)
defer cancel() defer cancel()
// Get the reverse proxy for this instance // Get instance options to build the health check URL
proxy, err := i.GetProxy() opts := i.GetOptions()
if err != nil { if opts == nil {
return fmt.Errorf("failed to get proxy for instance %s: %w", i.Name, err) return fmt.Errorf("instance %s has no options set", i.Name)
} }
// Polling interval // Build the health check URL directly
ticker := time.NewTicker(1 * time.Second) host := opts.Host
defer ticker.Stop() if host == "" {
host = "localhost"
}
healthURL := fmt.Sprintf("http://%s:%d/health", host, opts.Port)
// Helper function to check health using the proxy // Create a dedicated HTTP client for health checks
client := &http.Client{
Timeout: 5 * time.Second, // 5 second timeout per request
}
// Helper function to check health directly
checkHealth := func() bool { checkHealth := func() bool {
// Create a request to /health req, err := http.NewRequestWithContext(ctx, "GET", healthURL, nil)
req, err := http.NewRequestWithContext(ctx, "GET", "/health", nil)
if err != nil { if err != nil {
return false return false
} }
// Create a custom ResponseRecorder to capture the proxy response resp, err := client.Do(req)
recorder := &healthResponseRecorder{ if err != nil {
statusCode: 0, return false
headers: make(http.Header),
} }
defer resp.Body.Close()
// Use the proxy to forward the request return resp.StatusCode == http.StatusOK
proxy.ServeHTTP(recorder, req)
return recorder.statusCode == http.StatusOK
} }
// Try immediate check first // Try immediate check first
@@ -191,6 +196,9 @@ func (i *Process) WaitForHealthy(timeout int) error {
} }
// If immediate check failed, start polling // If immediate check failed, start polling
ticker := time.NewTicker(1 * time.Second)
defer ticker.Stop()
for { for {
select { select {
case <-ctx.Done(): case <-ctx.Done():
@@ -204,25 +212,6 @@ func (i *Process) WaitForHealthy(timeout int) error {
} }
} }
// healthResponseRecorder implements http.ResponseWriter to capture proxy responses
type healthResponseRecorder struct {
statusCode int
headers http.Header
}
func (r *healthResponseRecorder) Header() http.Header {
return r.headers
}
func (r *healthResponseRecorder) Write([]byte) (int, error) {
// We don't need to capture the body for health checks
return 0, nil
}
func (r *healthResponseRecorder) WriteHeader(statusCode int) {
r.statusCode = statusCode
}
func (i *Process) monitorProcess() { func (i *Process) monitorProcess() {
defer func() { defer func() {
i.mu.Lock() i.mu.Lock()