From d381360dfb1e07bd23caa634432554d935261ea2 Mon Sep 17 00:00:00 2001 From: zxr <271055687@qq.com> Date: Sat, 18 Jul 2026 08:51:58 +0800 Subject: [PATCH] fix: honor alert forwarding business responses --- internal/ingest/alert_forward.go | 37 +++++++++++++++++++++++++++----- internal/ingest/alert_outbox.go | 22 +------------------ 2 files changed, 33 insertions(+), 26 deletions(-) diff --git a/internal/ingest/alert_forward.go b/internal/ingest/alert_forward.go index f78f9d1..067fc18 100644 --- a/internal/ingest/alert_forward.go +++ b/internal/ingest/alert_forward.go @@ -4,6 +4,7 @@ import ( "bytes" "encoding/json" "fmt" + "io" "net/http" "strings" "time" @@ -11,6 +12,8 @@ import ( "git.apinb.com/ops/logs/internal/config" ) +const alertResponseBodyLimit = 1 << 20 + // AlertReceiveBody 与 alert ReceiveRequest 对齐(含必填 raw_data) type AlertReceiveBody struct { AlertName string `json:"alert_name"` @@ -57,10 +60,13 @@ func forwardAlert(body AlertReceiveBody) error { if err != nil { return err } - url := cfg.BaseURL + "/Alert/v1/alerts/receive" - req, err := http.NewRequest(http.MethodPost, url, bytes.NewReader(raw)) + return postAlertPayload(cfg, "/Alert/v1/alerts/receive", raw) +} + +func postAlertPayload(cfg *config.AlertForwardConf, path string, payload []byte) error { + req, err := http.NewRequest(http.MethodPost, cfg.BaseURL+path, bytes.NewReader(payload)) if err != nil { - return err + return fmt.Errorf("创建 Alert 转发请求失败:%w", err) } req.Header.Set("Content-Type", "application/json") if cfg.InternalKey != "" { @@ -69,11 +75,32 @@ func forwardAlert(body AlertReceiveBody) error { client := &http.Client{Timeout: 10 * time.Second} resp, err := client.Do(req) if err != nil { - return err + return fmt.Errorf("发送 Alert 转发请求失败:%w", err) } defer resp.Body.Close() + + responseBody, err := io.ReadAll(io.LimitReader(resp.Body, alertResponseBodyLimit+1)) + if err != nil { + return fmt.Errorf("读取 Alert 响应失败:%w", err) + } + if len(responseBody) > alertResponseBodyLimit { + return fmt.Errorf("Alert 响应体超过 %d 字节限制,请稍后重试", alertResponseBodyLimit) + } if resp.StatusCode != http.StatusOK { - return fmt.Errorf("alert returned HTTP %d", resp.StatusCode) + return fmt.Errorf("Alert 返回 HTTP %d,请稍后重试", resp.StatusCode) + } + + var result struct { + Code *int32 `json:"code"` + } + if err := json.Unmarshal(responseBody, &result); err != nil { + return fmt.Errorf("Alert 响应不是有效 JSON:%v;请稍后重试", err) + } + if result.Code == nil { + return fmt.Errorf("Alert 响应缺少 code,无法确认转发成功;请稍后重试") + } + if *result.Code != 0 { + return fmt.Errorf("Alert 拒绝转发,业务 code=%d;请稍后重试", *result.Code) } return nil } diff --git a/internal/ingest/alert_outbox.go b/internal/ingest/alert_outbox.go index a00e5bf..b349c60 100644 --- a/internal/ingest/alert_outbox.go +++ b/internal/ingest/alert_outbox.go @@ -1,10 +1,8 @@ package ingest import ( - "bytes" "encoding/json" "fmt" - "net/http" "strings" "time" @@ -118,25 +116,7 @@ func forwardRawEvent(body RawEventIngestBody) error { if err != nil { return err } - url := cfg.BaseURL + "/Alert/v1/raw-events/ingest" - req, err := http.NewRequest(http.MethodPost, url, bytes.NewReader(raw)) - if err != nil { - return err - } - req.Header.Set("Content-Type", "application/json") - if cfg.InternalKey != "" { - req.Header.Set("X-Internal-Key", cfg.InternalKey) - } - client := &http.Client{Timeout: 10 * time.Second} - resp, err := client.Do(req) - if err != nil { - return err - } - defer resp.Body.Close() - if resp.StatusCode != http.StatusOK { - return fmt.Errorf("alert returned HTTP %d", resp.StatusCode) - } - return nil + return postAlertPayload(cfg, "/Alert/v1/raw-events/ingest", raw) } func markOutboxRetry(row models.AlertOutbox, msg string) {