后端: 1.接入主动调度 worker 与飞书通知链路 - 新增 due job scanner 与 active_schedule.triggered workflow - 接入 notification.feishu.requested handler、飞书 webhook provider 和用户通知配置接口 - 支持 notification_records 去重、重试、skipped/dead 状态流转 - 完成 api / worker / all 启动模式装配与主动调度验收记录 2.后续要做的就是补全从异常发生到给用户推送消息之间的逻辑缺口
89 lines
4.0 KiB
Go
89 lines
4.0 KiB
Go
package notification
|
||
|
||
import "context"
|
||
|
||
const (
|
||
// ChannelFeishu 表示当前通知记录走飞书通道。
|
||
ChannelFeishu = "feishu"
|
||
)
|
||
|
||
const (
|
||
// FeishuErrorCodeProviderTimeout 表示 provider 超时,属于可重试错误。
|
||
FeishuErrorCodeProviderTimeout = "provider_timeout"
|
||
// FeishuErrorCodeProviderRateLimited 表示 provider 限流,属于可重试错误。
|
||
FeishuErrorCodeProviderRateLimited = "provider_rate_limited"
|
||
// FeishuErrorCodeProvider5xx 表示 provider 服务端异常,属于可重试错误。
|
||
FeishuErrorCodeProvider5xx = "provider_5xx"
|
||
// FeishuErrorCodeNetworkError 表示网络层异常,属于可重试错误。
|
||
FeishuErrorCodeNetworkError = "network_error"
|
||
// FeishuErrorCodeRecipientMissing 表示缺少接收方,属于不可恢复错误。
|
||
FeishuErrorCodeRecipientMissing = "recipient_missing"
|
||
// FeishuErrorCodeInvalidURL 表示目标链接非法,属于不可恢复错误。
|
||
FeishuErrorCodeInvalidURL = "invalid_url"
|
||
// FeishuErrorCodeProviderAuthFailed 表示 provider 认证失败,属于不可恢复错误。
|
||
FeishuErrorCodeProviderAuthFailed = "provider_auth_failed"
|
||
// FeishuErrorCodePayloadInvalid 表示请求体非法,属于不可恢复错误。
|
||
FeishuErrorCodePayloadInvalid = "payload_invalid"
|
||
)
|
||
|
||
// FeishuSendOutcome 表示 provider 对一次投递尝试的分类结果。
|
||
//
|
||
// 职责边界:
|
||
// 1. 只表达 provider 层对“这次投递”是否成功、是否可重试的判断;
|
||
// 2. 不直接承载 notification_records 的状态机,状态流转由 NotificationService 决定;
|
||
// 3. future webhook/open_id provider 只要返回同一套枚举,即可复用现有重试逻辑。
|
||
type FeishuSendOutcome string
|
||
|
||
const (
|
||
FeishuSendOutcomeSuccess FeishuSendOutcome = "success"
|
||
FeishuSendOutcomeTemporaryFail FeishuSendOutcome = "temporary_fail"
|
||
FeishuSendOutcomePermanentFail FeishuSendOutcome = "permanent_fail"
|
||
FeishuSendOutcomeSkipped FeishuSendOutcome = "skipped"
|
||
)
|
||
|
||
// FeishuSendRequest 是通知服务传给 provider 的稳定输入。
|
||
//
|
||
// 职责边界:
|
||
// 1. 只描述 provider 真正发消息所需的信息;
|
||
// 2. 不暴露 GORM model,避免 provider 依赖数据库细节;
|
||
// 3. 同时保留审计字段,方便 mock/webhook provider 记录请求摘要。
|
||
type FeishuSendRequest struct {
|
||
NotificationID int64 `json:"notification_id"`
|
||
UserID int `json:"user_id"`
|
||
TriggerID string `json:"trigger_id"`
|
||
PreviewID string `json:"preview_id"`
|
||
TriggerType string `json:"trigger_type"`
|
||
TargetType string `json:"target_type"`
|
||
TargetID int `json:"target_id"`
|
||
TargetURL string `json:"target_url"`
|
||
MessageText string `json:"message_text"`
|
||
FallbackUsed bool `json:"fallback_used"`
|
||
TraceID string `json:"trace_id,omitempty"`
|
||
AttemptCount int `json:"attempt_count"`
|
||
}
|
||
|
||
// FeishuSendResult 是 provider 对外返回的投递结果。
|
||
//
|
||
// 职责边界:
|
||
// 1. outcome 决定 NotificationService 应该进入 sent / failed / dead 中哪一条路径;
|
||
// 2. request/response payload 仅用于落库审计,不要求与任意具体 SDK 强绑定;
|
||
// 3. error_code 需要尽量稳定,便于后续按错误码做告警和排障。
|
||
type FeishuSendResult struct {
|
||
Outcome FeishuSendOutcome `json:"outcome"`
|
||
ProviderMessageID string `json:"provider_message_id,omitempty"`
|
||
ErrorCode string `json:"error_code,omitempty"`
|
||
ErrorMessage string `json:"error_message,omitempty"`
|
||
RequestPayload any `json:"request_payload,omitempty"`
|
||
ResponsePayload any `json:"response_payload,omitempty"`
|
||
}
|
||
|
||
// FeishuProvider 是飞书投递能力的抽象边界。
|
||
//
|
||
// 职责边界:
|
||
// 1. 负责把最终文案发给具体 provider;
|
||
// 2. 不负责 notification_records 的创建、去重、状态机和重试节奏;
|
||
// 3. 后续新增 WebhookFeishuProvider / OpenIDFeishuProvider 时,只需实现这个接口。
|
||
type FeishuProvider interface {
|
||
Send(ctx context.Context, req FeishuSendRequest) (FeishuSendResult, error)
|
||
}
|