Version: 0.9.68.dev.260504
后端: 1. 阶段 3 notification 服务边界落地,新增 `cmd/notification`、`services/notification`、`gateway/notification`、`shared/contracts/notification` 和 notification port,按 userauth 同款最小手搓 zrpc 样板收口 2. notification outbox consumer、relay 和 retry loop 迁入独立服务入口,处理 `notification.feishu.requested`,gateway 改为通过 zrpc client 调用 notification 3. 清退旧单体 notification DAO/model/service/provider/runner 和 `service/events/notification_feishu.go`,旧实现不再作为活跃编译路径 4. 修复 outbox 路由归属、dispatch 启动扫描、Kafka topic 探测/投递超时、sending 租约恢复、毒消息 MarkDead 错误回传和 RPC timeout 边界 5. 同步调整 active-scheduler 触发通知事件、核心 outbox handler、MySQL 迁移边界和 notification 配置 文档: 1. 更新微服务迁移计划,将阶段 3 notification 标记为已完成,并明确下一阶段从 active-scheduler 开始
This commit is contained in:
@@ -66,21 +66,6 @@ const (
|
||||
ActiveScheduleApplyStatusExpired = "expired"
|
||||
)
|
||||
|
||||
const (
|
||||
// NotificationRecordStatusPending 表示通知记录已落库,等待投递。
|
||||
NotificationRecordStatusPending = "pending"
|
||||
// NotificationRecordStatusSending 表示当前 worker 正在调用 provider。
|
||||
NotificationRecordStatusSending = "sending"
|
||||
// NotificationRecordStatusSent 表示 provider 明确返回成功。
|
||||
NotificationRecordStatusSent = "sent"
|
||||
// NotificationRecordStatusFailed 表示本次投递失败,但仍可重试。
|
||||
NotificationRecordStatusFailed = "failed"
|
||||
// NotificationRecordStatusDead 表示达到重试上限或不可恢复错误。
|
||||
NotificationRecordStatusDead = "dead"
|
||||
// NotificationRecordStatusSkipped 表示命中去重或配置关闭,本次不投递。
|
||||
NotificationRecordStatusSkipped = "skipped"
|
||||
)
|
||||
|
||||
const (
|
||||
// ActiveScheduleTriggerTypeImportantUrgentTask 是重要且紧急任务到线触发。
|
||||
ActiveScheduleTriggerTypeImportantUrgentTask = "important_urgent_task"
|
||||
@@ -221,44 +206,3 @@ type ActiveSchedulePreview struct {
|
||||
}
|
||||
|
||||
func (ActiveSchedulePreview) TableName() string { return "active_schedule_previews" }
|
||||
|
||||
// NotificationRecord 是通知投递记录表模型。
|
||||
//
|
||||
// 职责边界:
|
||||
// 1. 负责记录飞书等通知渠道的幂等、状态流转和 provider 返回;
|
||||
// 2. 不负责决定是否生成调度预览,也不负责 apply 状态;
|
||||
// 3. 重试时复用同一条记录,避免短时间重复打扰用户。
|
||||
type NotificationRecord struct {
|
||||
ID int64 `gorm:"column:id;primaryKey;autoIncrement"`
|
||||
|
||||
Channel string `gorm:"column:channel;type:varchar(32);not null;uniqueIndex:uk_notification_dedupe,priority:1;comment:通知渠道"`
|
||||
UserID int `gorm:"column:user_id;not null;index:idx_notification_user_created,priority:1"`
|
||||
TriggerID string `gorm:"column:trigger_id;type:varchar(64);not null;index:idx_notification_trigger"`
|
||||
PreviewID string `gorm:"column:preview_id;type:varchar(64);not null;index:idx_notification_preview"`
|
||||
TriggerType string `gorm:"column:trigger_type;type:varchar(64);not null"`
|
||||
TargetType string `gorm:"column:target_type;type:varchar(64);not null"`
|
||||
TargetID int `gorm:"column:target_id;not null"`
|
||||
DedupeKey string `gorm:"column:dedupe_key;type:varchar(191);not null;uniqueIndex:uk_notification_dedupe,priority:2"`
|
||||
TargetURL string `gorm:"column:target_url;type:varchar(255);not null;comment:站内预览链接"`
|
||||
SummaryText string `gorm:"column:summary_text;type:text"`
|
||||
FallbackText string `gorm:"column:fallback_text;type:text"`
|
||||
FallbackUsed bool `gorm:"column:fallback_used;not null;default:false"`
|
||||
Status string `gorm:"column:status;type:varchar(32);not null;default:'pending';index:idx_notification_status_retry,priority:1;comment:pending/sending/sent/failed/dead/skipped"`
|
||||
AttemptCount int `gorm:"column:attempt_count;not null;default:0"`
|
||||
MaxAttempts int `gorm:"column:max_attempts;not null;default:5"`
|
||||
NextRetryAt *time.Time `gorm:"column:next_retry_at;index:idx_notification_status_retry,priority:2"`
|
||||
LastErrorCode *string `gorm:"column:last_error_code;type:varchar(64)"`
|
||||
LastError *string `gorm:"column:last_error;type:text"`
|
||||
|
||||
ProviderMessageID *string `gorm:"column:provider_message_id;type:varchar(128)"`
|
||||
ProviderRequestJSON *string `gorm:"column:provider_request_json;type:json"`
|
||||
ProviderResponseJSON *string `gorm:"column:provider_response_json;type:json"`
|
||||
SentAt *time.Time `gorm:"column:sent_at"`
|
||||
TraceID string `gorm:"column:trace_id;type:varchar(64);index:idx_notification_trace_id"`
|
||||
|
||||
CreatedAt time.Time `gorm:"column:created_at;autoCreateTime;index:idx_notification_user_created,priority:2"`
|
||||
UpdatedAt time.Time `gorm:"column:updated_at;autoUpdateTime"`
|
||||
DeletedAt gorm.DeletedAt `gorm:"column:deleted_at;index"`
|
||||
}
|
||||
|
||||
func (NotificationRecord) TableName() string { return "notification_records" }
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
// NotificationChannelFeishuWebhook 表示用户配置的是飞书 Webhook 触发器。
|
||||
NotificationChannelFeishuWebhook = "feishu_webhook"
|
||||
)
|
||||
|
||||
const (
|
||||
// NotificationAuthTypeNone 表示 webhook 不需要额外鉴权头。
|
||||
NotificationAuthTypeNone = "none"
|
||||
// NotificationAuthTypeBearer 表示 webhook 需要 Authorization: Bearer token。
|
||||
NotificationAuthTypeBearer = "bearer"
|
||||
)
|
||||
|
||||
// UserNotificationChannel 保存单个用户的外部通知通道配置。
|
||||
//
|
||||
// 职责边界:
|
||||
// 1. 只记录 user_id 到具体通知 provider 配置的映射;
|
||||
// 2. 不记录 notification_records 投递状态,投递状态仍属于 NotificationRecord;
|
||||
// 3. 当前 webhook_url / bearer_token 暂以明文字段承载,接口和日志必须脱敏;后续接入统一密钥加密能力后再替换存储实现。
|
||||
type UserNotificationChannel struct {
|
||||
ID int64 `gorm:"column:id;primaryKey;autoIncrement" json:"id"`
|
||||
|
||||
UserID int `gorm:"column:user_id;not null;uniqueIndex:uk_user_notification_channel,priority:1;index:idx_user_notification_channel_user"`
|
||||
Channel string `gorm:"column:channel;type:varchar(32);not null;uniqueIndex:uk_user_notification_channel,priority:2"`
|
||||
Enabled bool `gorm:"column:enabled;not null;default:true"`
|
||||
WebhookURL string `gorm:"column:webhook_url;type:text;not null"`
|
||||
AuthType string `gorm:"column:auth_type;type:varchar(32);not null;default:'none'"`
|
||||
BearerToken string `gorm:"column:bearer_token;type:text;not null"`
|
||||
|
||||
LastTestStatus string `gorm:"column:last_test_status;type:varchar(32)"`
|
||||
LastTestError string `gorm:"column:last_test_error;type:text"`
|
||||
LastTestAt *time.Time `gorm:"column:last_test_at"`
|
||||
|
||||
CreatedAt time.Time `gorm:"column:created_at;autoCreateTime"`
|
||||
UpdatedAt time.Time `gorm:"column:updated_at;autoUpdateTime"`
|
||||
}
|
||||
|
||||
func (UserNotificationChannel) TableName() string { return "user_notification_channels" }
|
||||
Reference in New Issue
Block a user