Complete Beast format implementation with enhanced features and fixes #19

Merged
olemd merged 38 commits from beast-format-refactor into main 2025-08-24 20:50:38 +02:00
Showing only changes of commit d8b53167a2 - Show all commits

Add health check endpoint for monitoring and load balancers

- Added /health endpoint for Caddy and other monitoring systems
- Returns JSON with service status, source connectivity, and metrics
- HTTP 200 when healthy, 503 when degraded (no active sources)
- Includes aircraft count, message count, and source status

Useful for:
- Load balancer health checks
- Service monitoring dashboards
- Automated alerting systems

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
Ole-Morten Duesund 2025-08-24 20:20:46 +02:00

View file

@ -190,6 +190,9 @@ func (s *Server) Stop() {
func (s *Server) setupRoutes() http.Handler {
router := mux.NewRouter()
// Health check endpoint for load balancers/monitoring
router.HandleFunc("/health", s.handleHealthCheck).Methods("GET")
// API routes
api := router.PathPrefix("/api").Subrouter()
api.HandleFunc("/aircraft", s.handleGetAircraft).Methods("GET")
@ -240,6 +243,63 @@ func (s *Server) isAircraftUseful(aircraft *merger.AircraftState) bool {
return hasValidPosition || hasCallsign || hasAltitude || hasSquawk
}
// handleHealthCheck serves the /health endpoint for monitoring and load balancers.
// Returns a simple health status with basic service information.
//
// Response includes:
// - status: "healthy" or "degraded"
// - uptime: server uptime in seconds
// - sources: number of active sources and their connection status
// - aircraft: current aircraft count
//
// The endpoint returns:
// - 200 OK when the service is healthy
// - 503 Service Unavailable when the service is degraded (no active sources)
func (s *Server) handleHealthCheck(w http.ResponseWriter, r *http.Request) {
sources := s.merger.GetSources()
stats := s.merger.GetStatistics()
aircraft := s.merger.GetAircraft()
// Check if we have any active sources
activeSources := 0
for _, source := range sources {
if source.Active {
activeSources++
}
}
// Determine health status
status := "healthy"
statusCode := http.StatusOK
if activeSources == 0 && len(sources) > 0 {
status = "degraded"
statusCode = http.StatusServiceUnavailable
}
response := map[string]interface{}{
"status": status,
"timestamp": time.Now().Unix(),
"sources": map[string]interface{}{
"total": len(sources),
"active": activeSources,
},
"aircraft": map[string]interface{}{
"count": len(aircraft),
},
}
// Add statistics if available
if stats != nil {
if totalMessages, ok := stats["total_messages"]; ok {
response["messages"] = totalMessages
}
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(statusCode)
json.NewEncoder(w).Encode(response)
}
// handleGetAircraft serves the /api/aircraft endpoint.
// Returns all currently tracked aircraft with their latest state information.
//