From 835b92ec002c1e4c0824dccc1641081e57097084 Mon Sep 17 00:00:00 2001 From: ryan Date: Sat, 27 Jun 2026 13:32:33 +0800 Subject: [PATCH] fix: wire retry into router, fix Docker config path, fix condition error handling, remove dead code --- Dockerfile | 2 +- internal/engine/router.go | 15 ++++++--------- internal/handler/notify.go | 29 ++++++++++++++++++----------- 3 files changed, 25 insertions(+), 21 deletions(-) diff --git a/Dockerfile b/Dockerfile index 6f32215..ed8b761 100644 --- a/Dockerfile +++ b/Dockerfile @@ -10,7 +10,7 @@ FROM alpine:3.20 RUN apk add --no-cache ca-certificates tzdata COPY --from=builder /server /usr/local/bin/server -COPY config/config.yaml /etc/notification/config.yaml +COPY config/config.yaml /config/config.yaml EXPOSE 8080 ENTRYPOINT ["server"] diff --git a/internal/engine/router.go b/internal/engine/router.go index 98890c0..522f29f 100644 --- a/internal/engine/router.go +++ b/internal/engine/router.go @@ -9,16 +9,10 @@ import ( "aiaa-notification-service/internal/adapter" "aiaa-notification-service/internal/cache" "aiaa-notification-service/internal/model" + "aiaa-notification-service/internal/retry" "aiaa-notification-service/internal/store" ) -type SendResult struct { - ChannelType string `json:"channel_type"` - ChannelID int `json:"channel_id"` - Success bool `json:"success"` - Error string `json:"error,omitempty"` -} - type Router struct { store *store.Store cache *cache.Cache @@ -51,8 +45,11 @@ func (r *Router) Route(ctx context.Context, rule *model.Rule, title, content str if ch.Config != nil { cfg = *ch.Config } - if err := s.Send(title, content, cfg); err != nil { - slog.Error("send failed", "channel_type", ch.Type, "channel_id", ch.ID, "error", err) + r := retry.DefaultRetrier() + if err := r.Do(context.Background(), func() error { + return s.Send(title, content, cfg) + }); err != nil { + slog.Error("send failed after retries", "channel_type", ch.Type, "channel_id", ch.ID, "error", err) } else { slog.Info("sent", "channel_type", ch.Type, "channel_id", ch.ID) } diff --git a/internal/handler/notify.go b/internal/handler/notify.go index 310651a..44f1765 100644 --- a/internal/handler/notify.go +++ b/internal/handler/notify.go @@ -1,6 +1,7 @@ package handler import ( + "context" "encoding/json" "io" "log/slog" @@ -63,15 +64,18 @@ func (h *NotifyHandler) Handle(c *gin.Context) { // 4. Evaluate conditions if rule.Conditions != nil { var conds []model.Condition - if err := json.Unmarshal(*rule.Conditions, &conds); err == nil { - if !condition.Evaluate(conds, msg.Data) { - c.JSON(http.StatusOK, gin.H{ - "matched": true, - "filtered": true, - "reason": "condition not met", - }) - return - } + if err := json.Unmarshal(*rule.Conditions, &conds); err != nil { + slog.Error("failed to unmarshal rule conditions", "rule_id", rule.ID, "error", err) + c.JSON(http.StatusUnprocessableEntity, gin.H{"error": "invalid rule conditions"}) + return + } + if !condition.Evaluate(conds, msg.Data) { + c.JSON(http.StatusOK, gin.H{ + "matched": true, + "filtered": true, + "reason": "condition not met", + }) + return } } @@ -93,9 +97,10 @@ func (h *NotifyHandler) Handle(c *gin.Context) { title := src.Name + ": " + msg.Event channels := h.router.Route(c.Request.Context(), rule, title, content) - // 8. Log message (best effort) + // 8. Log message (best effort, detached context) go func() { payloadJSON, _ := json.Marshal(msg.Data) + ctx := context.Background() for _, chName := range channels { chID := parseChannelID(chName) ml := &model.MessageLog{ @@ -107,7 +112,9 @@ func (h *NotifyHandler) Handle(c *gin.Context) { Content: content, Status: "pending", } - _ = h.store.CreateMessageLog(c.Request.Context(), ml) + if err := h.store.CreateMessageLog(ctx, ml); err != nil { + slog.Warn("failed to create message log", "error", err) + } } }()