From 30b926add431f41c57e4c972190920fe3884401e Mon Sep 17 00:00:00 2001 From: erio Date: Sun, 12 Apr 2026 12:50:27 +0800 Subject: [PATCH] fix(notify): per-recipient timeout and return user on email removal - Use per-recipient context timeout in sendEmails to prevent later recipients from failing due to shared timeout exhaustion - Return updated user object from RemoveNotifyEmail handler for frontend state consistency (matching VerifyNotifyEmail pattern) --- backend/internal/handler/user_handler.go | 9 ++++++++- backend/internal/service/balance_notify_service.go | 4 ++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/backend/internal/handler/user_handler.go b/backend/internal/handler/user_handler.go index 42463a7a..4fb72ce7 100644 --- a/backend/internal/handler/user_handler.go +++ b/backend/internal/handler/user_handler.go @@ -205,5 +205,12 @@ func (h *UserHandler) RemoveNotifyEmail(c *gin.Context) { return } - response.Success(c, gin.H{"message": "Email removed successfully"}) + // Return updated user + updatedUser, err := h.userService.GetByID(c.Request.Context(), subject.UserID) + if err != nil { + response.ErrorFrom(c, err) + return + } + + response.Success(c, dto.UserFromService(updatedUser)) } diff --git a/backend/internal/service/balance_notify_service.go b/backend/internal/service/balance_notify_service.go index 8223a231..8dd56b8f 100644 --- a/backend/internal/service/balance_notify_service.go +++ b/backend/internal/service/balance_notify_service.go @@ -186,13 +186,13 @@ func (s *BalanceNotifyService) collectBalanceNotifyRecipients(user *User) []stri // sendEmails sends an email to all recipients with shared timeout and error logging. func (s *BalanceNotifyService) sendEmails(recipients []string, subject, body string, logAttrs ...any) { - ctx, cancel := context.WithTimeout(context.Background(), emailSendTimeout) - defer cancel() for _, to := range recipients { + ctx, cancel := context.WithTimeout(context.Background(), emailSendTimeout) if err := s.emailService.SendEmail(ctx, to, subject, body); err != nil { attrs := append([]any{"to", to, "error", err}, logAttrs...) slog.Error("failed to send notification", attrs...) } + cancel() } }