发送通知时写入数据库
This commit is contained in:
@@ -33,6 +33,7 @@ type failoverService struct {
|
||||
primaryNotifier notify.Notifier
|
||||
failureThreshold int
|
||||
failureCounters *sync.Map // 使用 sync.Map 来安全地并发读写失败计数, key: userID (uint), value: counter (int)
|
||||
notificationRepo repository.NotificationRepository
|
||||
}
|
||||
|
||||
// NewFailoverService 创建一个新的故障转移通知服务
|
||||
@@ -42,6 +43,7 @@ func NewFailoverService(
|
||||
notifiers []notify.Notifier,
|
||||
primaryNotifierType notify.NotifierType,
|
||||
failureThreshold int,
|
||||
notificationRepo repository.NotificationRepository,
|
||||
) (Service, error) {
|
||||
notifierMap := make(map[notify.NotifierType]notify.Notifier)
|
||||
for _, n := range notifiers {
|
||||
@@ -60,6 +62,7 @@ func NewFailoverService(
|
||||
primaryNotifier: primaryNotifier,
|
||||
failureThreshold: failureThreshold,
|
||||
failureCounters: &sync.Map{},
|
||||
notificationRepo: notificationRepo,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -128,11 +131,15 @@ func (s *failoverService) sendAlarmToUser(userID uint, content notify.AlarmConte
|
||||
primaryType := s.primaryNotifier.Type()
|
||||
addr := getAddressForNotifier(primaryType, user.Contact)
|
||||
if addr == "" {
|
||||
// 记录跳过通知
|
||||
s.recordNotificationAttempt(userID, primaryType, content, "", models.NotificationStatusSkipped, fmt.Errorf("用户未配置首选通知方式 '%s' 的地址", primaryType))
|
||||
return fmt.Errorf("用户未配置首选通知方式 '%s' 的地址", primaryType)
|
||||
}
|
||||
|
||||
err = s.primaryNotifier.Send(content, addr)
|
||||
if err == nil {
|
||||
// 记录成功通知
|
||||
s.recordNotificationAttempt(userID, primaryType, content, addr, models.NotificationStatusSuccess, nil)
|
||||
if failureCount > 0 {
|
||||
s.log.Infow("首选渠道发送恢复正常", "userID", userID, "notifierType", primaryType)
|
||||
s.failureCounters.Store(userID, 0)
|
||||
@@ -140,6 +147,8 @@ func (s *failoverService) sendAlarmToUser(userID uint, content notify.AlarmConte
|
||||
return nil
|
||||
}
|
||||
|
||||
// 记录失败通知
|
||||
s.recordNotificationAttempt(userID, primaryType, content, addr, models.NotificationStatusFailed, err)
|
||||
newFailureCount := failureCount + 1
|
||||
s.failureCounters.Store(userID, newFailureCount)
|
||||
s.log.Warnw("首选渠道发送失败", "userID", userID, "notifierType", primaryType, "error", err, "failureCount", newFailureCount)
|
||||
@@ -152,13 +161,19 @@ func (s *failoverService) sendAlarmToUser(userID uint, content notify.AlarmConte
|
||||
for _, notifier := range s.notifiers {
|
||||
addr := getAddressForNotifier(notifier.Type(), user.Contact)
|
||||
if addr == "" {
|
||||
// 记录跳过通知
|
||||
s.recordNotificationAttempt(userID, notifier.Type(), content, "", models.NotificationStatusSkipped, fmt.Errorf("用户未配置通知方式 '%s' 的地址", notifier.Type()))
|
||||
continue
|
||||
}
|
||||
if err := notifier.Send(content, addr); err == nil {
|
||||
// 记录成功通知
|
||||
s.recordNotificationAttempt(userID, notifier.Type(), content, addr, models.NotificationStatusSuccess, nil)
|
||||
s.log.Infow("广播通知成功", "userID", userID, "notifierType", notifier.Type())
|
||||
s.failureCounters.Store(userID, 0)
|
||||
return nil
|
||||
}
|
||||
// 记录失败通知
|
||||
s.recordNotificationAttempt(userID, notifier.Type(), content, addr, models.NotificationStatusFailed, err)
|
||||
lastErr = err
|
||||
s.log.Warnw("广播通知:渠道发送失败", "userID", userID, "notifierType", notifier.Type(), "error", err)
|
||||
}
|
||||
@@ -185,6 +200,13 @@ func (s *failoverService) SendTestMessage(userID uint, notifierType notify.Notif
|
||||
addr := getAddressForNotifier(notifierType, user.Contact)
|
||||
if addr == "" {
|
||||
s.log.Warnw("发送测试消息失败:缺少地址", "userID", userID, "notifierType", notifierType)
|
||||
// 记录跳过通知
|
||||
s.recordNotificationAttempt(userID, notifierType, notify.AlarmContent{
|
||||
Title: "通知服务测试",
|
||||
Message: fmt.Sprintf("这是一条来自【%s】渠道的测试消息。如果您收到此消息,说明您的配置正确。", notifierType),
|
||||
Level: zap.InfoLevel,
|
||||
Timestamp: time.Now(),
|
||||
}, "", models.NotificationStatusFailed, fmt.Errorf("用户未配置通知方式 '%s' 的地址", notifierType))
|
||||
return fmt.Errorf("用户未配置通知方式 '%s' 的地址", notifierType)
|
||||
}
|
||||
|
||||
@@ -199,10 +221,14 @@ func (s *failoverService) SendTestMessage(userID uint, notifierType notify.Notif
|
||||
err = notifier.Send(testContent, addr)
|
||||
if err != nil {
|
||||
s.log.Errorw("发送测试消息失败", "userID", userID, "notifierType", notifierType, "error", err)
|
||||
// 记录失败通知
|
||||
s.recordNotificationAttempt(userID, notifierType, testContent, addr, models.NotificationStatusFailed, err)
|
||||
return err
|
||||
}
|
||||
|
||||
s.log.Infow("发送测试消息成功", "userID", userID, "notifierType", notifierType)
|
||||
// 记录成功通知
|
||||
s.recordNotificationAttempt(userID, notifierType, testContent, addr, models.NotificationStatusSuccess, nil)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -221,3 +247,46 @@ func getAddressForNotifier(notifierType notify.NotifierType, contact models.Cont
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
// recordNotificationAttempt 记录一次通知发送尝试的结果
|
||||
// userID: 接收通知的用户ID
|
||||
// notifierType: 使用的通知器类型
|
||||
// content: 通知内容
|
||||
// toAddress: 实际发送到的地址
|
||||
// status: 发送尝试的状态 (成功、失败、跳过)
|
||||
// err: 如果发送失败,记录的错误信息
|
||||
func (s *failoverService) recordNotificationAttempt(
|
||||
userID uint,
|
||||
notifierType notify.NotifierType,
|
||||
content notify.AlarmContent,
|
||||
toAddress string,
|
||||
status models.NotificationStatus,
|
||||
err error,
|
||||
) {
|
||||
errorMessage := ""
|
||||
if err != nil {
|
||||
errorMessage = err.Error()
|
||||
}
|
||||
|
||||
notification := &models.Notification{
|
||||
NotifierType: notifierType,
|
||||
UserID: userID,
|
||||
Title: content.Title,
|
||||
Message: content.Message,
|
||||
Level: content.Level,
|
||||
AlarmTimestamp: content.Timestamp,
|
||||
ToAddress: toAddress,
|
||||
Status: status,
|
||||
ErrorMessage: errorMessage,
|
||||
}
|
||||
|
||||
if saveErr := s.notificationRepo.Create(notification); saveErr != nil {
|
||||
s.log.Errorw("无法保存通知发送记录到数据库",
|
||||
"userID", userID,
|
||||
"notifierType", notifierType,
|
||||
"status", status,
|
||||
"originalError", errorMessage,
|
||||
"saveError", saveErr,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user