package aggregate import ( "context" "net/http" "time" ) // effectiveConnectionsBad возвращает значение для порогов инцидентов: прирост от последнего сброса. func (h *Handler) effectiveConnectionsBad(alias string, current uint64) uint64 { h.badConnBaselineMu.Lock() defer h.badConnBaselineMu.Unlock() b, ok := h.badConnBaseline[alias] if !ok { return current } if current < b { // Счётчик на ноде уменьшился (перезапуск и т.п.) — старая отметка неприменима. delete(h.badConnBaseline, alias) return current } return current - b } func (h *Handler) setBadConnectionBaseline(alias string, snapshot uint64) { h.badConnBaselineMu.Lock() defer h.badConnBaselineMu.Unlock() if h.badConnBaseline == nil { h.badConnBaseline = make(map[string]uint64) } h.badConnBaseline[alias] = snapshot } // HandleResetBadConnectionsBaseline — POST /api/agg/bad-connections/reset // Сохраняет текущий connections_bad_total по каждой выбранной ноде как нулевую отметку для алертов. func (h *Handler) HandleResetBadConnectionsBaseline(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodPost { w.Header().Set("Allow", http.MethodPost) http.Error(w, "method not allowed", http.StatusMethodNotAllowed) return } aliases, err := h.resolveAliases(r) if err != nil { writeBadRequest(w, err) return } ctx, cancel := context.WithTimeout(r.Context(), 60*time.Second) defer cancel() type row struct { Alias string `json:"alias"` OK bool `json:"ok"` Baseline uint64 `json:"baseline,omitempty"` Error string `json:"error,omitempty"` } rows := make([]row, 0, len(aliases)) partial := false for _, alias := range aliases { data, meta := FetchTelemtGET[statsSummaryLite](ctx, h.Client, h.Parsed, alias, "stats/summary") if !meta.OK { partial = true rows = append(rows, row{Alias: alias, OK: false, Error: meta.Error}) continue } h.setBadConnectionBaseline(alias, data.ConnectionsBadTotal) rows = append(rows, row{Alias: alias, OK: true, Baseline: data.ConnectionsBadTotal}) } writeAggOK(w, partial, map[string]any{"servers": rows}) }