feat(T1.8): implement health checks for Kubernetes deployment
- Add internal/health package with health checker - Implement three endpoints: /health, /health/live, /health/ready - /health returns full JSON report with component status, latency, timestamp - /health/live for K8s liveness probe (service running) - /health/ready for K8s readiness probe (ready to accept traffic) - Temporal connectivity check via GetWorkflow call with timeout - Health check caching (30s interval) to prevent excessive checks - Graceful shutdown: health server stops on SIGINT/SIGTERM - Add --health flag to starter command to run health check - Worker runs health server on port 8081 alongside task queue worker - 10/10 unit tests passing - All verification criteria met Closes T1.8
This commit is contained in:
+54
-3
@@ -1,13 +1,20 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"go.temporal.io/sdk/client"
|
||||
"go.temporal.io/sdk/worker"
|
||||
"github.com/rockliang/poimen/workflows/action"
|
||||
"github.com/rockliang/poimen/workflows/internal/config"
|
||||
"github.com/rockliang/poimen/workflows/internal/health"
|
||||
"github.com/rockliang/poimen/workflows/statemachine"
|
||||
)
|
||||
|
||||
@@ -55,9 +62,53 @@ func main() {
|
||||
// w.RegisterActivity(action.UpdateLessonsActivity)
|
||||
// w.RegisterActivity(action.ReadLessonsActivity)
|
||||
|
||||
// Run worker
|
||||
fmt.Println("Starting worker on queue 'poimen-taskqueue'...")
|
||||
if err := w.Run(worker.InterruptCh()); err != nil {
|
||||
// Initialize health checker
|
||||
healthChecker := health.NewChecker(c)
|
||||
healthHandler := health.NewHandler(healthChecker)
|
||||
|
||||
// Set up HTTP server for health checks
|
||||
mux := http.NewServeMux()
|
||||
healthHandler.RegisterRoutes(mux)
|
||||
|
||||
healthServer := &http.Server{
|
||||
Addr: ":8081",
|
||||
Handler: mux,
|
||||
}
|
||||
|
||||
// Start health check server in a goroutine
|
||||
go func() {
|
||||
log.Printf("Health check server listening on %s", healthServer.Addr)
|
||||
if err := healthServer.ListenAndServe(); err != nil && err != http.ErrServerClosed {
|
||||
log.Printf("health check server error: %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
// Set up signal handling for graceful shutdown
|
||||
sigChan := make(chan os.Signal, 1)
|
||||
signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)
|
||||
|
||||
// Run worker in a goroutine
|
||||
workerErrChan := make(chan error, 1)
|
||||
go func() {
|
||||
fmt.Println("Starting worker on queue 'poimen-taskqueue'...")
|
||||
if err := w.Run(worker.InterruptCh()); err != nil {
|
||||
workerErrChan <- err
|
||||
}
|
||||
}()
|
||||
|
||||
// Wait for either worker error or signal
|
||||
select {
|
||||
case err := <-workerErrChan:
|
||||
log.Fatalf("worker failed: %v", err)
|
||||
case sig := <-sigChan:
|
||||
log.Printf("received signal: %v, shutting down gracefully", sig)
|
||||
w.Stop()
|
||||
|
||||
// Shutdown health check server
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
defer cancel()
|
||||
if err := healthServer.Shutdown(ctx); err != nil {
|
||||
log.Printf("health check server shutdown error: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user