mirror of
https://github.com/Wei-Shaw/sub2api.git
synced 2026-09-21 14:19:18 +08:00
feat(ops): 新增 account_temp_unscheduled_count 告警指标
临时摘除(temp-unschedulable)的账号被 account_error_count 指标显式排除 (acc.HasError && TempUnschedulableUntil == nil),且 SetTempUnschedulable 不 改账号 Status,导致代理/凭据故障触发的自动摘除无法被现有告警覆盖。 新增 account_temp_unscheduled_count 指标,统计当前处于临时不可调度窗口 (TempUnschedulableUntil 未过期) 的账号数,打通对自动摘除的定向告警: - evaluator computeRuleMetric 新增分支 + handler 允许列表; - 前端联合类型、告警规则下拉项与 en/zh 文案同步。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
217f85999c
commit
f20e6bf769
@@ -29,6 +29,7 @@ var validOpsAlertMetricTypes = []string{
|
||||
"account_rate_limited_count",
|
||||
"account_error_count",
|
||||
"account_error_ratio",
|
||||
"account_temp_unscheduled_count",
|
||||
"overload_account_count",
|
||||
}
|
||||
|
||||
|
||||
@@ -506,6 +506,18 @@ func (s *OpsAlertEvaluatorService) computeRuleMetric(
|
||||
return float64(countAccountsByCondition(availability.Accounts, func(acc *AccountAvailability) bool {
|
||||
return acc.HasError && acc.TempUnschedulableUntil == nil
|
||||
})), true
|
||||
case "account_temp_unscheduled_count":
|
||||
if s == nil || s.opsService == nil {
|
||||
return 0, false
|
||||
}
|
||||
availability, err := s.opsService.GetAccountAvailability(ctx, platform, groupID)
|
||||
if err != nil || availability == nil {
|
||||
return 0, false
|
||||
}
|
||||
now := time.Now().UTC()
|
||||
return float64(countAccountsByCondition(availability.Accounts, func(acc *AccountAvailability) bool {
|
||||
return acc.TempUnschedulableUntil != nil && now.Before(*acc.TempUnschedulableUntil)
|
||||
})), true
|
||||
case "group_rate_limit_ratio":
|
||||
if groupID == nil || *groupID <= 0 {
|
||||
return 0, false
|
||||
|
||||
@@ -106,6 +106,48 @@ func TestCountAccountsByCondition(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
// TestComputeRuleMetric_AccountTempUnscheduledCount verifies the new
|
||||
// account_temp_unscheduled_count metric counts accounts currently in the
|
||||
// temp-unscheduled window and ignores those whose window has expired or
|
||||
// were never temp-unscheduled.
|
||||
func TestComputeRuleMetric_AccountTempUnscheduledCount(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
now := time.Now().UTC()
|
||||
futureUntil := now.Add(5 * time.Minute)
|
||||
pastUntil := now.Add(-1 * time.Minute)
|
||||
|
||||
availability := &OpsAccountAvailability{
|
||||
Accounts: map[int64]*AccountAvailability{
|
||||
// currently temp-unscheduled (window active)
|
||||
1: {TempUnschedulableUntil: &futureUntil},
|
||||
2: {TempUnschedulableUntil: &futureUntil},
|
||||
// temp-unsched window already expired → should NOT count
|
||||
3: {TempUnschedulableUntil: &pastUntil},
|
||||
// never temp-unscheduled
|
||||
4: {HasError: true},
|
||||
5: {IsRateLimited: true},
|
||||
},
|
||||
}
|
||||
|
||||
opsService := &OpsService{
|
||||
getAccountAvailability: func(_ context.Context, _ string, _ *int64) (*OpsAccountAvailability, error) {
|
||||
return availability, nil
|
||||
},
|
||||
}
|
||||
svc := &OpsAlertEvaluatorService{
|
||||
opsService: opsService,
|
||||
opsRepo: &stubOpsRepo{},
|
||||
}
|
||||
|
||||
rule := &OpsAlertRule{MetricType: "account_temp_unscheduled_count"}
|
||||
val, ok := svc.computeRuleMetric(context.Background(), rule, nil,
|
||||
now.Add(-5*time.Minute), now, "", nil)
|
||||
|
||||
require.True(t, ok)
|
||||
require.InDelta(t, 2.0, val, 0.0001, "only 2 accounts have an active temp-unsched window")
|
||||
}
|
||||
|
||||
func TestComputeRuleMetricNewIndicators(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
|
||||
@@ -685,6 +685,7 @@ export type MetricType =
|
||||
| 'account_rate_limited_count'
|
||||
| 'account_error_count'
|
||||
| 'account_error_ratio'
|
||||
| 'account_temp_unscheduled_count'
|
||||
| 'overload_account_count'
|
||||
export type Operator = '>' | '>=' | '<' | '<=' | '==' | '!='
|
||||
|
||||
|
||||
@@ -5028,6 +5028,7 @@ export default {
|
||||
accountRateLimitedCount: 'Rate-limited Accounts',
|
||||
accountErrorCount: 'Error Accounts (excluding temporarily unschedulable)',
|
||||
accountErrorRatio: 'Error Account Ratio (%)',
|
||||
accountTempUnscheduledCount: 'Temporarily Unschedulable Accounts',
|
||||
overloadAccountCount: 'Overloaded Accounts'
|
||||
},
|
||||
metricDescriptions: {
|
||||
@@ -5045,6 +5046,7 @@ export default {
|
||||
accountRateLimitedCount: 'Number of rate-limited accounts within the window.',
|
||||
accountErrorCount: 'Number of error accounts within the window (excluding temporarily unschedulable).',
|
||||
accountErrorRatio: 'Error account ratio within the window (0-100).',
|
||||
accountTempUnscheduledCount: 'Number of accounts currently temporarily unschedulable (e.g. proxy/credential failure auto-eviction).',
|
||||
overloadAccountCount: 'Number of overloaded accounts within the window.'
|
||||
},
|
||||
hints: {
|
||||
|
||||
@@ -5187,6 +5187,7 @@ export default {
|
||||
accountRateLimitedCount: '限流账号数',
|
||||
accountErrorCount: '错误账号数(不含临时不可调度)',
|
||||
accountErrorRatio: '错误账号比例 (%)',
|
||||
accountTempUnscheduledCount: '临时不可调度账号数',
|
||||
overloadAccountCount: '过载账号数'
|
||||
},
|
||||
metricDescriptions: {
|
||||
@@ -5204,6 +5205,7 @@ export default {
|
||||
accountRateLimitedCount: '统计窗口内被限流的账号数量。',
|
||||
accountErrorCount: '统计窗口内产生错误的账号数量(不含临时不可调度)。',
|
||||
accountErrorRatio: '统计窗口内错误账号占比(0~100)。',
|
||||
accountTempUnscheduledCount: '当前处于临时不可调度状态的账号数量(如代理/凭据故障被自动摘除)。',
|
||||
overloadAccountCount: '统计窗口内过载账号数量。'
|
||||
},
|
||||
hints: {
|
||||
|
||||
@@ -221,6 +221,14 @@ const metricDefinitions = computed(() => {
|
||||
recommendedThreshold: 5,
|
||||
unit: '%'
|
||||
},
|
||||
{
|
||||
type: 'account_temp_unscheduled_count',
|
||||
group: 'account',
|
||||
label: t('admin.ops.alertRules.metrics.accountTempUnscheduledCount'),
|
||||
description: t('admin.ops.alertRules.metricDescriptions.accountTempUnscheduledCount'),
|
||||
recommendedOperator: '>',
|
||||
recommendedThreshold: 0
|
||||
},
|
||||
{
|
||||
type: 'overload_account_count',
|
||||
group: 'account',
|
||||
|
||||
Reference in New Issue
Block a user