将 River 执行容量按平台模型与用户组的有效并发策略动态调整,并为长任务续租、并发租约原子抢占和限流退避补充保护。\n\n统一平台模型限流继承语义,兼容历史 platformLimits/modelLimits,并为三个迁移图像模型建立独立并发租约。补充管理端显式继承/覆盖配置、指标、单元测试及隔离 PostgreSQL 验收。\n\n验证:go test ./... -count=1;pnpm lint;pnpm test;pnpm build;隔离 PostgreSQL 并发原子性/续租测试;128 任务与三分钟长任务动态 Worker 验收。
61 lines
2.2 KiB
Go
61 lines
2.2 KiB
Go
package securityevents
|
|
|
|
import (
|
|
"context"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
type metricsSnapshot struct {
|
|
mode string
|
|
last time.Time
|
|
}
|
|
|
|
func (m metricsSnapshot) SecurityEventMetrics(context.Context, string, string) (string, *time.Time, error) {
|
|
return m.mode, &m.last, nil
|
|
}
|
|
|
|
func TestMetricsExposeBoundedOutcomesAndState(t *testing.T) {
|
|
metrics := &Metrics{}
|
|
metrics.ObserveReceipt("accepted", 20*time.Millisecond, 2)
|
|
metrics.ObserveReceipt("duplicate", 10*time.Millisecond, 0)
|
|
metrics.ObserveWatermarkRejection()
|
|
metrics.ObserveHeartbeat("accepted")
|
|
metrics.ObserveIntrospection("failed")
|
|
metrics.ObserveJWKSRefreshFailure("ssf")
|
|
metrics.SetAsyncWorkerCapacity(96, 128, 96, true)
|
|
metrics.ObserveAsyncWorkerResize("success")
|
|
metrics.ObserveConcurrencyLeaseRenewal("success")
|
|
metrics.ObserveConcurrencyLeaseRenewal("lost")
|
|
|
|
recorder := httptest.NewRecorder()
|
|
metrics.Handler(metricsSnapshot{mode: "push_healthy", last: time.Now().Add(-time.Minute)}, "issuer", "audience", true).
|
|
ServeHTTP(recorder, httptest.NewRequest(http.MethodGet, "/metrics", nil))
|
|
if recorder.Code != http.StatusOK {
|
|
t.Fatalf("metrics status=%d", recorder.Code)
|
|
}
|
|
for _, expected := range []string{
|
|
`easyai_gateway_ssf_receipts_total{outcome="accepted"} 1`,
|
|
`easyai_gateway_ssf_receipts_total{outcome="duplicate"} 1`,
|
|
`easyai_gateway_ssf_sessions_deleted_total 2`,
|
|
`easyai_gateway_ssf_watermark_rejections_total 1`,
|
|
`easyai_gateway_ssf_processing_duration_seconds_bucket{le="0.05"} 2`,
|
|
`easyai_gateway_ssf_mode{mode="push_healthy"} 1`,
|
|
`easyai_gateway_oidc_introspection_total{outcome="failed"} 1`,
|
|
`easyai_gateway_jwks_refresh_failures_total{outcome="ssf"} 1`,
|
|
`easyai_gateway_async_worker_capacity 96`,
|
|
`easyai_gateway_async_worker_desired_capacity 128`,
|
|
`easyai_gateway_async_worker_capacity_capped 1`,
|
|
`easyai_gateway_async_worker_resizes_total{outcome="success"} 1`,
|
|
`easyai_gateway_concurrency_lease_renewals_total{outcome="success"} 1`,
|
|
`easyai_gateway_concurrency_lease_renewals_total{outcome="lost"} 1`,
|
|
} {
|
|
if !strings.Contains(recorder.Body.String(), expected) {
|
|
t.Fatalf("missing metric %q in:\n%s", expected, recorder.Body.String())
|
|
}
|
|
}
|
|
}
|