notify

package
v0.1.4 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 4, 2026 License: Apache-2.0 Imports: 12 Imported by: 0

Documentation

Overview

Package notify 负责把任务状态变化投递到预注册的 Webhook 目标。

设计要点:调用方只能提供目标名(Target),URL 与密钥都保存在服务端的注册表里。 这不是省事,而是安全边界——如果回调 URL 由调用方指定,它就能被当作探测内网、 盗取凭证的通道;配套的 SSRF 防护与出网白名单也随之省掉。

投递语义是 at-least-once:网络超时等服务端无法判定结果的场景下,接收方可能收到 重复请求。因此每条通知带稳定的 X-OFD-Delivery 头,接收方据此幂等去重。

Index

Constants

View Source
const (
	EventSucceeded = "succeeded"
	EventFailed    = "failed"
	// EventWildcard 在订阅列表里表示"全部事件",与配置侧同一套写法。
	EventWildcard = "*"
)

事件名。

View Source
const (
	HeaderDelivery   = "X-OFD-Delivery"
	HeaderEvent      = "X-OFD-Event"
	HeaderJob        = "X-OFD-Job"
	HeaderTimestamp  = "X-OFD-Timestamp"
	HeaderSignature  = "X-OFD-Signature"
	SignatureVersion = "v1"
)

投递所用的请求头。

View Source
const DefaultTimeout = 10 * time.Second

DefaultTimeout 是单次投递的默认超时。

刻意比一般 HTTP 客户端短:通知是旁路,接收方卡住不应该拖住队列。超过这个时间 就当作失败退避重试,反正 at-least-once 允许重复。

Variables

View Source
var ErrEventNotSubscribed = errors.New("通知目标未订阅该事件")

ErrEventNotSubscribed 表示目标未订阅该事件。这不算错误:目标就是不要这个事件。

View Source
var ErrTargetNotFound = errors.New("通知目标未注册")

ErrTargetNotFound 表示目标未注册。调用方据此拒绝请求,而不是静默丢弃。

Functions

func KnownEvent

func KnownEvent(name string) bool

KnownEvent 判断 name 是不是受支持的事件名。

供提交阶段校验调用方的 notify.events 用。接线之后一个拼错的事件名会让该 任务一条通知都收不到,而调用方唯一的线索是"没收到"——所以拼错必须在提交 阶段就报错,不能等到投递时静默过滤掉。

func Retryable

func Retryable(err error) bool

Retryable 报告该失败是否值得重试。

func Signer

func Signer(secret string, body []byte, timestamp time.Time) string

Signer 生成 Webhook 签名头。

签名覆盖 时间戳 + "." + 原始请求体,接收方用同一密钥重算并常量时间比较。 时间戳让同一份请求体无法被无限期重放。

func Subscribes

func Subscribes(events []string, event string) bool

Subscribes 判断订阅列表是否覆盖该事件。

列表为空表示不收窄——这正是 notify.events 与 Target.Events 共用的语义: 留空则沿用目标自己的订阅集合。

两个来源都过这一处:两个字段同名同义,各写一份判定迟早漂移。

func Verify

func Verify(secret string, header string, body []byte, timestamp time.Time) bool

Verify 校验签名,供接收方或测试使用。

Types

type Deliverer

type Deliverer struct {
	// contains filtered or unexported fields
}

Deliverer 按注册表投递通知。

func NewDeliverer

func NewDeliverer(registry *Registry, client *http.Client) *Deliverer

NewDeliverer 构造投递器。client 为 nil 时按目标超时创建客户端。

func (*Deliverer) Deliver

func (d *Deliverer) Deliver(ctx context.Context, req Request) error

Deliver 投递一条通知。

重试由调用方(jobstore)负责:这里只区分可重试与不可重试的失败, 不可重试的 4xx 会终止重试,把消息直接判死。

func (*Deliverer) SetClock

func (d *Deliverer) SetClock(now func() time.Time)

SetClock 替换时钟,仅用于测试。

type Error

type Error struct {
	Delivery  string
	Status    int
	Retryable bool
	Err       error
}

Error 是投递失败。

func (*Error) Error

func (e *Error) Error() string

func (*Error) Unwrap

func (e *Error) Unwrap() error

type Registry

type Registry struct {
	// contains filtered or unexported fields
}

Registry 持有已注册的目标。注册后只读,构造完成后可被多个投递协程共享。

func NewRegistry

func NewRegistry(targets map[string]Target) *Registry

NewRegistry 注册目标。同名目标会覆盖,便于配置热更新。

func (*Registry) Lookup

func (r *Registry) Lookup(name string) (Target, bool)

Lookup 返回目标。

func (*Registry) Names

func (r *Registry) Names() []string

Names 返回全部已注册的目标名,供管理接口列举。

type Request

type Request struct {
	// Target 是已注册的目标名,不是 URL。
	Target string
	// ID 稳定唯一,作为去重标识。
	ID string
	// JobID 关联的转换任务。
	JobID string
	// Event 见 EventSucceeded / EventFailed。
	Event string
	// Payload 请求体,会原样发送。
	Payload []byte
	// Attempt 当前是第几次尝试,从 1 开始。
	Attempt int
}

Request 是一次投递所需的全部信息。

type Target

type Target struct {
	// URL 完整回调地址。仅服务端可见。
	URL string
	// Secret 用于 HMAC-SHA256 签名的密钥;为空表示不签名(仅建议本地调试用)。
	Secret string
	// Events 订阅的事件名白名单,空表示订阅全部。
	Events []string
	// Timeout 单次投递超时,0 时取 DefaultTimeout。
	Timeout time.Duration
}

Target 是一个已注册的通知目标。

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL