perf: quick wins for pipeline, jobs, httpapi and web ops

- CDN snapshot: batch merge после parallel fetch, без race на persist
- ListRevisionPrefixes: лёгкая проверка revision вместо GetRevision
- Jobs: timeout/cancel context для pipeline и deploy
- HTTP server timeouts; кэш birdc для GET /peers
- ListModules: batch DoH profiles одним запросом
- Web: tab-scoped load на /operations, debounce job search, меньше over-fetch на dashboard

Co-authored-by: Cursor <[email protected]>
This commit is contained in:
Denozordec
2026-05-21 10:42:13 +07:00
co-authored by Cursor
parent 5fca165c69
commit be3d73f374
13 changed files with 425 additions and 34 deletions
+39 -1
View File
@@ -82,6 +82,12 @@ var (
})
)
var (
birdProtocolStatesMu sync.RWMutex
birdProtocolStates map[string]string
birdProtocolStatesAt time.Time
)
// RecordPrefixAggregation records tenant render CIDR aggregation stats.
func RecordPrefixAggregation(rawCount, aggregatedCount int, duration time.Duration) {
if rawCount < 0 {
@@ -205,6 +211,35 @@ func SetBirdSessionMetrics(established int, scrapeOK bool) {
}
}
// SetBirdProtocolStates caches parsed BGP protocol states from the last birdc scrape.
func SetBirdProtocolStates(states map[string]string) {
birdProtocolStatesMu.Lock()
defer birdProtocolStatesMu.Unlock()
if states == nil {
birdProtocolStates = map[string]string{}
} else {
birdProtocolStates = states
}
birdProtocolStatesAt = time.Now()
}
// CachedBirdProtocolStates returns cached protocol states if younger than maxAge.
func CachedBirdProtocolStates(maxAge time.Duration) (map[string]string, bool) {
if maxAge <= 0 {
maxAge = 60 * time.Second
}
birdProtocolStatesMu.RLock()
defer birdProtocolStatesMu.RUnlock()
if birdProtocolStates == nil || time.Since(birdProtocolStatesAt) > maxAge {
return nil, false
}
out := make(map[string]string, len(birdProtocolStates))
for k, v := range birdProtocolStates {
out[k] = v
}
return out, true
}
// MetricsHandler returns the Prometheus scrape handler.
func MetricsHandler() http.Handler {
return promhttp.HandlerFor(prometheus.DefaultGatherer, promhttp.HandlerOpts{})
@@ -231,7 +266,7 @@ func (s *statusRecorder) WriteHeader(code int) {
// StartBirdProtocolsPoller runs birdc "show protocols" on interval when socket is non-empty.
// Горутина завершается при отмене ctx (корректное завершение вместе с процессом API).
func StartBirdProtocolsPoller(ctx context.Context, socket string, birdcPath string, interval time.Duration, showFn func(ctx context.Context, socket, birdcBin string) (string, error), countFn func(output string) int) {
func StartBirdProtocolsPoller(ctx context.Context, socket string, birdcPath string, interval time.Duration, showFn func(ctx context.Context, socket, birdcBin string) (string, error), countFn func(output string) int, parseFn func(output string) map[string]string) {
socket = trimSpace(socket)
if ctx == nil || socket == "" || interval <= 0 || showFn == nil || countFn == nil {
return
@@ -245,6 +280,9 @@ func StartBirdProtocolsPoller(ctx context.Context, socket string, birdcPath stri
return
}
SetBirdSessionMetrics(countFn(out), true)
if parseFn != nil {
SetBirdProtocolStates(parseFn(out))
}
}
go func() {
scrape()