Feat v0.6.4 health metrics (#39)
All checks were successful
All checks were successful
Co-authored-by: Jeffrey Smith <jasafpro@gmail.com> Co-committed-by: Jeffrey Smith <jasafpro@gmail.com>
This commit was merged in pull request #39.
This commit is contained in:
@@ -56,6 +56,7 @@ func main() {
|
||||
}
|
||||
|
||||
// ── Server startup ──────────────────────
|
||||
startTime := time.Now()
|
||||
cfg := config.Load()
|
||||
|
||||
// Structured logging — must be first so all subsequent
|
||||
@@ -200,19 +201,40 @@ func main() {
|
||||
// ── WebSocket Hub ─────────────────────────
|
||||
hub := events.NewHub(bus, middleware.GetAllowedOrigins(cfg))
|
||||
|
||||
// ── Node Identity ────────────────
|
||||
// Used by cluster registry (PG) and metrics endpoint (all deployments).
|
||||
nodeID := cfg.ClusterNodeID
|
||||
if nodeID == "" {
|
||||
hostname, _ := os.Hostname()
|
||||
nodeID = fmt.Sprintf("%s-%d", hostname, os.Getpid())
|
||||
}
|
||||
|
||||
// ── Cluster Registry ────────────
|
||||
// PG-backed node self-registration + heartbeat. No-op on SQLite.
|
||||
var clusterReg *cluster.Registry
|
||||
if database.IsPostgres() && stores.Cluster != nil {
|
||||
nodeID := cfg.ClusterNodeID
|
||||
if nodeID == "" {
|
||||
hostname, _ := os.Hostname()
|
||||
nodeID = fmt.Sprintf("%s-%d", hostname, os.Getpid())
|
||||
}
|
||||
clusterReg = cluster.NewRegistry(nodeID, cfg.ClusterEndpoint, stores.Cluster, hub, cluster.RegistryConfig{
|
||||
HeartbeatInterval: cfg.ClusterHeartbeatInterval,
|
||||
StaleThreshold: cfg.ClusterStaleThreshold,
|
||||
})
|
||||
clusterReg.SetSandboxStats(sandbox.SandboxStats)
|
||||
clusterReg.SetTriggerFireCount(triggerEngine.FireCount)
|
||||
clusterReg.SetExtensionCount(func() int {
|
||||
if stores.Packages == nil {
|
||||
return 0
|
||||
}
|
||||
pkgs, err := stores.Packages.List(context.Background())
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
count := 0
|
||||
for _, p := range pkgs {
|
||||
if p.Status == "active" {
|
||||
count++
|
||||
}
|
||||
}
|
||||
return count
|
||||
})
|
||||
if err := clusterReg.Start(); err != nil {
|
||||
log.Printf("⚠ Cluster registry failed to start: %v", err)
|
||||
clusterReg = nil
|
||||
@@ -255,7 +277,7 @@ func main() {
|
||||
}
|
||||
|
||||
// Health check (k8s probes hit this directly)
|
||||
base.GET("/health", func(c *gin.Context) {
|
||||
buildHealthResponse := func() gin.H {
|
||||
info := gin.H{
|
||||
"status": "ok",
|
||||
"version": Version,
|
||||
@@ -263,8 +285,15 @@ func main() {
|
||||
"database_name": database.Name(),
|
||||
"schema_version": database.SchemaVersion(),
|
||||
}
|
||||
if database.IsConnected() {
|
||||
info["registration_enabled"] = handlers.IsRegistrationEnabled(stores)
|
||||
}
|
||||
appendClusterHealth(info, clusterReg, stores)
|
||||
c.JSON(200, info)
|
||||
return info
|
||||
}
|
||||
|
||||
base.GET("/health", func(c *gin.Context) {
|
||||
c.JSON(200, buildHealthResponse())
|
||||
})
|
||||
|
||||
// Liveness: process is alive and serving (no dependency checks).
|
||||
@@ -352,20 +381,9 @@ func main() {
|
||||
|
||||
api := base.Group("/api/v1")
|
||||
{
|
||||
// Health (routable through ingress)
|
||||
// Health (routable through ingress — same shape as /health)
|
||||
api.GET("/health", func(c *gin.Context) {
|
||||
info := gin.H{
|
||||
"status": "ok",
|
||||
"version": Version,
|
||||
"schema_version": database.SchemaVersion(),
|
||||
"database": database.IsConnected(),
|
||||
"database_name": database.Name(),
|
||||
}
|
||||
if database.IsConnected() {
|
||||
info["registration_enabled"] = handlers.IsRegistrationEnabled(stores)
|
||||
}
|
||||
appendClusterHealth(info, clusterReg, stores)
|
||||
c.JSON(200, info)
|
||||
c.JSON(200, buildHealthResponse())
|
||||
})
|
||||
|
||||
authGroup := api.Group("/auth")
|
||||
@@ -794,6 +812,16 @@ func main() {
|
||||
admin.GET("/cluster", clusterH.ListNodes)
|
||||
}
|
||||
|
||||
// ── Metrics ─────────────────
|
||||
metricsCollector := metrics.NewCollector(
|
||||
nodeID, database.DB, hub, bus, stores,
|
||||
sandbox.SandboxStats,
|
||||
triggerEngine.FireCount,
|
||||
startTime,
|
||||
)
|
||||
metricsH := handlers.NewMetricsHandler(metricsCollector)
|
||||
admin.GET("/metrics", metricsH.GetMetrics)
|
||||
|
||||
// ── Backup/Restore ─────────
|
||||
backupH := handlers.NewBackupHandler(stores, packagesDir, cfg.StoragePath)
|
||||
admin.POST("/backup", backupH.CreateBackup)
|
||||
|
||||
Reference in New Issue
Block a user