Ver código fonte

feat: add runtime health alert

tags/v0.9.0
Jan Svabenik 1 mês atrás
pai
commit
b3e9f7bf45
5 arquivos alterados com 75 adições e 2 exclusões
  1. +1
    -0
      cmd/fmrtx/main.go
  2. +17
    -1
      internal/app/engine.go
  3. +50
    -0
      internal/app/runtime_indicator_test.go
  4. +3
    -0
      internal/control/control.go
  5. +4
    -1
      internal/control/control_test.go

+ 1
- 0
cmd/fmrtx/main.go Ver arquivo

@@ -256,6 +256,7 @@ func (b *txBridge) TXStats() map[string]any {
"maxWriteMs": s.MaxWriteMs,
"queue": s.Queue,
"runtimeIndicator": s.RuntimeIndicator,
"runtimeAlert": s.RuntimeAlert,
}
}
func (b *txBridge) UpdateConfig(lp ctrlpkg.LivePatch) error {


+ 17
- 1
internal/app/engine.go Ver arquivo

@@ -69,6 +69,7 @@ type EngineStats struct {
MaxWriteMs float64 `json:"maxWriteMs,omitempty"`
Queue output.QueueStats `json:"queue"`
RuntimeIndicator RuntimeIndicator `json:"runtimeIndicator"`
RuntimeAlert string `json:"runtimeAlert,omitempty"`
}

type RuntimeIndicator string
@@ -350,6 +351,7 @@ func (e *Engine) Stats() EngineStats {

queue := e.frameQueue.Stats()
lateBuffers := e.lateBuffers.Load()
ri := runtimeIndicator(queue.Health, lateBuffers)
return EngineStats{
State: state.String(),
ChunksProduced: e.chunksProduced.Load(),
@@ -363,7 +365,8 @@ func (e *Engine) Stats() EngineStats {
MaxUpsampleMs: durationMs(e.maxUpsampleNs.Load()),
MaxWriteMs: durationMs(e.maxWriteNs.Load()),
Queue: queue,
RuntimeIndicator: runtimeIndicator(queue.Health, lateBuffers),
RuntimeIndicator: ri,
RuntimeAlert: runtimeAlert(queue.Health, lateBuffers),
}
}

@@ -378,6 +381,19 @@ func runtimeIndicator(queueHealth output.QueueHealth, lateBuffers uint64) Runtim
}
}

func runtimeAlert(queueHealth output.QueueHealth, lateBuffers uint64) string {
switch {
case queueHealth == output.QueueHealthCritical:
return "queue health critical"
case lateBuffers > 0:
return "late buffers"
case queueHealth == output.QueueHealthLow:
return "queue health low"
default:
return ""
}
}

func (e *Engine) run(ctx context.Context) {
e.wg.Add(1)
go e.writerLoop(ctx)


+ 50
- 0
internal/app/runtime_indicator_test.go Ver arquivo

@@ -55,3 +55,53 @@ func TestRuntimeIndicator(t *testing.T) {
})
}
}

func TestRuntimeAlert(t *testing.T) {
cases := []struct {
name string
queueHealth output.QueueHealth
lateBuffers uint64
want string
}{
{
name: "normal",
queueHealth: output.QueueHealthNormal,
lateBuffers: 0,
want: "",
},
{
name: "lateBuffers",
queueHealth: output.QueueHealthNormal,
lateBuffers: 1,
want: "late buffers",
},
{
name: "queueLow",
queueHealth: output.QueueHealthLow,
lateBuffers: 0,
want: "queue health low",
},
{
name: "queueCritical",
queueHealth: output.QueueHealthCritical,
lateBuffers: 0,
want: "queue health critical",
},
{
name: "criticalLateBuffers",
queueHealth: output.QueueHealthCritical,
lateBuffers: 5,
want: "queue health critical",
},
}

for _, tc := range cases {
tc := tc
t.Run(tc.name, func(t *testing.T) {
if got := runtimeAlert(tc.queueHealth, tc.lateBuffers); got != tc.want {
t.Fatalf("runtime alert mismatch: queue=%s late=%d want=%q got=%q",
tc.queueHealth, tc.lateBuffers, tc.want, got)
}
})
}
}

+ 3
- 0
internal/control/control.go Ver arquivo

@@ -137,6 +137,9 @@ func (s *Server) handleStatus(w http.ResponseWriter, _ *http.Request) {
if ri, ok := stats["runtimeIndicator"]; ok {
status["runtimeIndicator"] = ri
}
if alert, ok := stats["runtimeAlert"]; ok {
status["runtimeAlert"] = alert
}
}
}



+ 4
- 1
internal/control/control_test.go Ver arquivo

@@ -39,7 +39,7 @@ func TestStatus(t *testing.T) {

func TestStatusReportsRuntimeIndicator(t *testing.T) {
srv := NewServer(cfgpkg.Default())
srv.SetTXController(&fakeTXController{stats: map[string]any{"runtimeIndicator": "degraded"}})
srv.SetTXController(&fakeTXController{stats: map[string]any{"runtimeIndicator": "degraded", "runtimeAlert": "late buffers"}})
rec := httptest.NewRecorder()
srv.Handler().ServeHTTP(rec, httptest.NewRequest(http.MethodGet, "/status", nil))
if rec.Code != 200 {
@@ -50,6 +50,9 @@ func TestStatusReportsRuntimeIndicator(t *testing.T) {
if body["runtimeIndicator"] != "degraded" {
t.Fatalf("expected runtimeIndicator degraded, got %v", body["runtimeIndicator"])
}
if body["runtimeAlert"] != "late buffers" {
t.Fatalf("expected runtimeAlert late buffers, got %v", body["runtimeAlert"])
}
}

func TestDryRunEndpoint(t *testing.T) {


Carregando…
Cancelar
Salvar