feat(渠道监控): 检测间隔支持正负随机抖动配置

新增 jitter_seconds 配置:每轮调度在 interval 基础上 ± [0, jitter]
均匀随机偏移触发,避免多个监控以固定节奏同步请求上游。

- ent schema 新增 jitter_seconds 字段(默认 0),附迁移 151
- 校验:jitter >= 0 且 interval - jitter >= 15s(创建/更新均校验)
- runner 由固定 ticker 改为每轮重新随机化的 timer,0 抖动时行为不变
- 前端监控表单新增「随机抖动 (± 秒)」输入框,上限随间隔联动

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
bwlcandClaude Fable 5 committed 2026-06-12 22:09:53 +08:00
1 parent e34ad2b194
commit c70c6a2659
21 files changed
+420 -11

No files matched your search

@@ -109,6 +109,12 @@
<p class="mt-1 text-xs text-gray-400">{{ t('admin.channelMonitor.form.intervalSecondsHint') }}</p>
</div>
<div>
<label class="input-label">{{ t('admin.channelMonitor.form.jitterSeconds') }}</label>
<input v-model.number="form.jitter_seconds" type="number" min="0" :max="maxJitterSeconds" class="input" />
<p class="mt-1 text-xs text-gray-400">{{ t('admin.channelMonitor.form.jitterSecondsHint') }}</p>
</div>
<div class="flex items-center justify-between">
<label class="input-label mb-0">{{ t('admin.channelMonitor.form.enabled') }}</label>
<Toggle v-model="form.enabled" />
@@ -254,6 +260,7 @@ interface MonitorForm {
extra_models: string[]
group_name: string
interval_seconds: number
jitter_seconds: number
enabled: boolean
// 高级设置快照
template_id: number | null
@@ -272,6 +279,7 @@ const form = reactive<MonitorForm>({
extra_models: [],
group_name: '',
interval_seconds: systemDefaultInterval.value,
jitter_seconds: 0,
enabled: true,
template_id: null,
extra_headers: {},
@@ -279,6 +287,9 @@ const form = reactive<MonitorForm>({
body_override: null,
})
// jitter 上限与后端校验一致:interval - jitter 不得低于最小检测间隔 15 秒。
const maxJitterSeconds = computed<number>(() => Math.max(0, (form.interval_seconds || 0) - 15))
let suppressFormWatchers = false
// 可用模板列表(进入 dialog 时一次性拉取 cache;按 provider / api mode 过滤)。
@@ -419,6 +430,7 @@ function resetForm() {
form.extra_models = []
form.group_name = ''
form.interval_seconds = systemDefaultInterval.value
form.jitter_seconds = 0
form.enabled = true
form.template_id = null
form.extra_headers = {}
@@ -438,6 +450,7 @@ function loadFromMonitor(m: ChannelMonitor) {
form.extra_models = [...(m.extra_models || [])]
form.group_name = m.group_name || ''
form.interval_seconds = m.interval_seconds || systemDefaultInterval.value
form.jitter_seconds = m.jitter_seconds || 0
form.enabled = m.enabled
form.template_id = m.template_id ?? null
form.extra_headers = { ...(m.extra_headers || {}) }
@@ -504,6 +517,7 @@ function buildPayload(): CreateParams {
group_name: form.group_name.trim(),
enabled: form.enabled,
interval_seconds: form.interval_seconds,
jitter_seconds: form.jitter_seconds || 0,
template_id: form.template_id,
extra_headers: form.extra_headers,
body_override_mode: form.body_override_mode,