package main import ( "context" "log" "os/signal" "syscall" "time" _ "github.com/go-sql-driver/mysql" "lingniu/vehicle-data-platform/apps/api/internal/config" "lingniu/vehicle-data-platform/apps/api/internal/platform" ) func main() { cfg := config.Load() if cfg.MySQLDSN == "" { log.Fatal("MYSQL_DSN is required") } ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM) defer stop() db, err := platform.OpenSQL(ctx, "mysql", cfg.MySQLDSN) if err != nil { log.Fatal(err) } defer db.Close() store := platform.NewProductionStore(db, nil, "").WithAlertStreamConfig(cfg.AlertStreamMode, cfg.AlertStreamKafkaGroup) service := platform.NewService(store) interval := cfg.AlertEvaluationInterval if interval < time.Second { interval = time.Second } ticker := time.NewTicker(interval) defer ticker.Stop() log.Printf("alert evaluator started interval=%s stream_mode=%s", interval, cfg.AlertStreamMode) for { started := time.Now() result, err := service.EvaluateAlerts(ctx) if err != nil { log.Printf("alert evaluation failed duration=%s error=%v", time.Since(started), err) } else { log.Printf("alert evaluation completed rules=%d vehicles=%d candidates_advanced=%d duplicate_observations=%d late_observations=%d stale_evidence_skipped=%d opened=%d recovered=%d duration=%s", result.RulesEvaluated, result.VehiclesScanned, result.CandidatesAdvanced, result.DuplicateObservations, result.LateObservations, result.StaleEvidenceSkipped, result.Opened, result.Recovered, time.Since(started)) } select { case <-ctx.Done(): log.Printf("alert evaluator stopped") return case <-ticker.C: } } }