当自动化任务执行结束并进入终态后,平台会向你在投递目标中配置的 Webhook 地址发起 HTTP POST 请求,推送本次执行结果。
投递时机:
终态 | 是否投递 |
执行成功( success) | 投递, event 为 task_success |
执行失败( failed) | 投递, event 为 task_failed |
执行超时( timeout) | 投递, event 为 task_timeout |
任务被主动取消 | 不投递 |
是否真正发出由投递目标的
events 订阅关系决定,见下文。事件订阅
投递目标可通过
events 声明只关心哪些终态:[{"type": "webhook","url": "https://your-domain.com/hook","events": ["failed", "timeout"]}]
配置 | 行为 |
events 为 ["failed"] | 仅在执行失败时投递 |
events 为 ["success", "failed", "timeout"] | 任何终态都投递 |
events 为空或未配置 | 按全订阅处理(成功、失败、超时都投递) |
取值仅支持
success / failed / timeout,大小写不敏感,前后空白会被忽略。订阅关系按目标独立生效,多个目标可以各配各的。
某目标未订阅本次终态时,不会发起请求,也不会记录投递失败信息。
请求头
Header | 是否必有 | 说明 |
Content-Type | 是 | 固定 application/json,不可覆盖 |
User-Agent | 是 | 固定 automation-scheduler/1.0 |
X-Webhook-Signature | 否 | HMAC-SHA256 签名(hex,小写),仅当投递目标配置了 secret 时携带 |
自定义 Header | 否 | 投递目标 headers 中配置的 KV |
Content-Type、User-Agent由平台统一下发,即使headers中配置了同名值也会被覆盖。
请求体示例
成功投递示例:
{"event": "task_success","taskNo": 2149837465201983489,"taskId": "task_abc123def456","taskName": "每日构建检查","logId": 2149837465201984001,"status": "success","result": "今日完成 5 项任务","durationMs": 30021,"timestamp": 1761120000000}
失败投递示例:
{"event": "task_failed","taskNo": 2149837465201983489,"taskId": "task_abc123def456","taskName": "每日构建检查","logId": 2149837465201984001,"status": "failed","errorMsg": "executor endpoint returned status 500","durationMs": 45210,"timestamp": 1761120000000}
字段 | 类型 | 是否必有 | 说明 |
event | string | 是 | 事件类型: task_success / task_failed / task_timeout |
taskNo | uint64 | 是 | 任务主键 ID(雪花 ID) |
taskId | string | 是 | 任务唯一标识(创建任务时指定的 key,账号内唯一) |
taskName | string | 是 | 任务名称 |
logId | uint64 | 是 | 本次执行日志 ID,可用于在控制台定位执行详情 |
status | string | 是 | 执行终态: success / failed / timeout |
result | string | 否 | 执行结果文本,成功且有产出时有值 |
errorMsg | string | 否 | 错误信息,失败/超时有值 |
durationMs | uint64 | 否 | 本次执行耗时(毫秒) |
timestamp | int64 | 是 | 投递时间戳,Unix 毫秒 |
说明:
taskNo / logId 为 64 位整数,超出 JavaScript Number 安全范围。若使用 JS/TS 接收,请按字符串或 BigInt 解析,否则会丢精度。若投递目标额外配置了
payload(如渠道类型、接收人 ID 等自定义字段),这些字段会合并进上述请求体的同一层级,与上表字段平级。result 为字符串,取值规则:执行结果形如 {"output": "..."} 时取 output 的值;否则取结果原文;无结果时省略该字段。响应要求
HTTP 状态码 | 含义 |
2xx | 投递成功 |
非 2xx | 投递失败 |
平台只读取状态码,不解析响应体。
有超时限制(默认 10 秒,服务端可配置),超时计为失败。
不做自动重试;失败原因会记录在本次执行日志中,可在控制台排查。
配置多个投递目标时,聚合结果可能为
success(全部成功)/ partial(部分成功)/ failed(全部失败)/ skipped(全部未订阅或未配置 URL)。签名验证
投递目标配置了
secret 时,平台会对请求的原始请求体字节做 HMAC-SHA256 签名,放入 X-Webhook-Signature 头,接收端可据此确认请求来自平台且内容未被篡改。项 | 值 |
算法 | HMAC-SHA256 |
密钥 | 你配置的 secret |
签名内容 | POST 请求的原始 JSON body(字节流,不做任何规范化) |
编码 | hex(小写) |
func verifyWebhookSignature(secret string, body []byte, signature string) bool {mac := hmac.New(sha256.New, []byte(secret))mac.Write(body)expected := hex.EncodeToString(mac.Sum(nil))return hmac.Equal([]byte(signature), []byte(expected))}// sig := r.Header.Get("X-Webhook-Signature")// body, _ := io.ReadAll(r.Body)// ok := verifyWebhookSignature("your-secret", body, sig)
import hmac, hashlibdef verify_webhook_signature(secret: str, body: bytes, signature: str) -> bool:expected = hmac.new(secret.encode(), body, hashlib.sha256).hexdigest()return hmac.compare_digest(signature, expected)# signature = request.headers.get("X-Webhook-Signature")# ok = verify_webhook_signature("your-secret", request.body, signature)
注意:
secret 未配置时不携带签名头,接收端无需验签。验签必须使用原始 body 字节流,先反序列化再序列化会因字段顺序、空格差异导致签名不一致。
建议使用常量时间比较(
hmac.Equal / hmac.compare_digest)防时序攻击。投递地址需通过平台的安全校验,指向内网/私有地址的 URL 会被拒绝投递。