feat: expose mysql transaction retry metrics

This commit is contained in:
2026-09-20 21:52:17 +08:00
parent a1e6fcc07f
commit ac8cc1260b
10 changed files with 55 additions and 4 deletions

View File

@@ -40,6 +40,8 @@ func catalog() map[string]descriptor {
}
c["orbit_db_wait_count_total"] = descriptor{counter, "Cumulative waits for a MySQL connection", nil}
c["orbit_db_wait_duration_seconds_total"] = descriptor{counter, "Cumulative seconds waiting for a MySQL connection", nil}
c["orbit_db_transaction_retries_total"] = descriptor{counter, "Cumulative pre-commit MySQL transaction retries", nil}
c["orbit_db_transaction_retry_exhausted_total"] = descriptor{counter, "Cumulative pre-commit MySQL transaction retry exhaustion", nil}
c["orbit_pulse_tasks_state"] = descriptor{gauge, "Bounded count of Pulse tasks by durable state", map[string][]string{"state": taskStates}}
c["orbit_pulse_tasks_oldest_age_seconds"] = descriptor{gauge, "Age of the oldest sampled unfinished Pulse task", nil}
c["orbit_result_deliveries_state"] = descriptor{gauge, "Bounded count of result deliveries by durable state", map[string][]string{"state": deliveryStates}}

View File

@@ -102,8 +102,9 @@ func TestRuntimeObservationDoesNotExposeErrors(t *testing.T) {
r.RecordBatch("workflow", time.Now(), errors.New("private-dsn"))
r.RecordBatch("schedule", time.Now(), context.Canceled)
r.RecordDatabase(sql.DBStats{MaxOpenConnections: 20, OpenConnections: 4, InUse: 3, Idle: 1, WaitCount: 9, WaitDuration: 2 * time.Second})
r.RecordTransactionStats(TransactionStats{Retries: 3, Exhausted: 1})
out := r.Render()
for _, want := range []string{`orbit_runtime_batch_total{component="workflow",outcome="success"} 1`, `orbit_runtime_batch_total{component="workflow",outcome="error"} 1`, `orbit_runtime_batch_total{component="schedule",outcome="cancelled"} 1`, "orbit_db_connections_in_use 3\n", "orbit_db_wait_duration_seconds_total 2\n"} {
for _, want := range []string{`orbit_runtime_batch_total{component="workflow",outcome="success"} 1`, `orbit_runtime_batch_total{component="workflow",outcome="error"} 1`, `orbit_runtime_batch_total{component="schedule",outcome="cancelled"} 1`, "orbit_db_connections_in_use 3\n", "orbit_db_wait_duration_seconds_total 2\n", "orbit_db_transaction_retries_total 3\n", "orbit_db_transaction_retry_exhausted_total 1\n"} {
if !strings.Contains(out, want) {
t.Fatal("missing runtime evidence", want)
}

View File

@@ -102,6 +102,9 @@ func (r *Registry) RecordBatch(component string, started time.Time, err error) {
// RecordDatabase reads the local connection-pool snapshot; it issues no SQL.
func (r *Registry) RecordDatabase(s sql.DBStats) {
if r == nil {
return
}
r.SetGauge("orbit_db_connections_open", float64(s.OpenConnections), nil)
r.SetGauge("orbit_db_connections_in_use", float64(s.InUse), nil)
r.SetGauge("orbit_db_connections_idle", float64(s.Idle), nil)
@@ -109,3 +112,18 @@ func (r *Registry) RecordDatabase(s sql.DBStats) {
r.SetCounter("orbit_db_wait_count_total", float64(s.WaitCount), nil)
r.SetCounter("orbit_db_wait_duration_seconds_total", s.WaitDuration.Seconds(), nil)
}
// TransactionStats 是本进程提交前事务重试的累计观测值。
type TransactionStats struct {
Retries uint64 // 已实际执行的重试次数。
Exhausted uint64 // 达到重试上限的事务次数。
}
// RecordTransactionStats records bounded database transaction retry counters.
func (r *Registry) RecordTransactionStats(stats TransactionStats) {
if r == nil {
return
}
r.SetCounter("orbit_db_transaction_retries_total", float64(stats.Retries), nil)
r.SetCounter("orbit_db_transaction_retry_exhausted_total", float64(stats.Exhausted), nil)
}