Files
EvoBGP/internal/pipeline/scheduler_due.go
T
DenozordecandCursor f8e0520817 feat(httpapi): harden control plane and speed up prefix refresh
Очередь job получила lease и fencing, телеметрия и прогресс deploy сохраняются, ревизия пишет manifest входов. Обновление префиксов не переписывает неизменённый снимок, большие наборы идут через COPY, а устаревшая ревизия не попадает в deploy. Бандл ноды кэшируется, prune и постановка job больше не держат горячий путь.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-11-02 17:23:59 +07:00

43 lines
1.2 KiB
Go

package pipeline
import (
"hash/fnv"
"time"
"evobgp/internal/store"
)
// SchedulerTickSec matches the scheduler ticker interval (internal/scheduler).
// The module refresh window stays at least 60s; a shorter tick only notices the boundary sooner.
const SchedulerTickSec = 10
// ModuleDueForScheduler reports whether a module's refresh interval bucket rolled since the last scheduler tick.
// A stable per-module offset (fnv32 of ID) spreads bucket boundaries so modules with the same interval
// do not all become due on the same tick (thundering herd).
func ModuleDueForScheduler(mod *store.Module, now time.Time) bool {
if mod == nil || !mod.Enabled || mod.Type == "IP_RANGES" || mod.RefreshIntervalSec <= 0 {
return false
}
win := int64(mod.RefreshIntervalSec)
if win < 60 {
win = 60
}
offset := moduleSchedulerOffset(mod.ID, win)
cur := (now.Unix() - offset) / win
prev := (now.Unix() - offset - SchedulerTickSec) / win
return cur != prev
}
func moduleSchedulerOffset(moduleID string, win int64) int64 {
if win <= 0 {
return 0
}
return int64(fnv32a(moduleID) % uint32(win))
}
func fnv32a(s string) uint32 {
h := fnv.New32a()
_, _ = h.Write([]byte(s))
return h.Sum32()
}