推送真发送:webhook/slack 内置真实发送端 + worker 终态自动通知

此前订阅与分发框架都在,但分发端点传 sender=None,
webhook/slack 永远报无 sender、从未真发过。本轮:
- push:send_webhook/send_slack(标准库 urllib POST,
  单次 10 秒超时,不重试,失败记 errors);sender=None
  时用内置端,显式 sender 优先;webpush/apns/fcm 仍报
  缺凭证(原因写明:webpush 需浏览器端三字段订阅与标准库
  没有的 P-256 ECDH + AES-GCM;apns 需 HTTP/2;fcm 需
  Firebase 服务账号,三者均无现成接收方,不造假发送)
- worker:run_one 终态(completed/failed,缺 key 与仓库
  失败两条早退路径也在内)后 best-effort 调分发,通知
  失败只记日志、绝不影响任务状态;取消(interrupted)
  不在事件集合里,不通知
- 测试:真实发送端 6 个(本地回环服务器)、worker 终态
  通知 2 个,旧无 sender 断言按新语义改写
This commit is contained in:
host committed 2026-10-26 17:31:30 +08:00
1 parent b7dace55b9
commit fb3a311da8
7 files changed
+429 -29

No files matched your search

+5 -3
View File
@@ -126,7 +126,7 @@ class OAuthPushEndpointsTestCase(unittest.TestCase):
pid = self.project["id"]
status, sub = self._req(
"POST", "/projects/%s/push/subscriptions" % pid,
{"channel": "webhook", "target": "https://example.invalid/hook",
{"channel": "webhook", "target": "http://127.0.0.1:1/hook",
"preference": "instant"},
self.owner_key)
self.assertEqual(status, 201, sub)
@@ -135,15 +135,17 @@ class OAuthPushEndpointsTestCase(unittest.TestCase):
key=self.owner_key)
self.assertEqual(status, 200)
self.assertEqual(len(body["subscriptions"]), 1)
# HTTP 层无注入 sender:分发应报“无 sender”,不静默成功。
# 内置真实发送端会真 POST:目标不可达时分发应报投递失败
# (不是“无 sender”,也不是静默成功),sent 为空。
status, body = self._req(
"POST", "/admin/push/dispatch",
{"event_type": "failed", "project_id": pid,
"payload": {"task_id": "t1"}},
self.owner_key)
self.assertEqual(status, 200)
self.assertEqual(body["sent"], [])
self.assertEqual(len(body["errors"]), 1)
self.assertIn("no sender", body["errors"][0]["reason"])
self.assertIn("delivery failed", body["errors"][0]["reason"])
# outsider 不能往别人项目里订阅/分发。
status, _ = self._req(
"POST", "/projects/%s/push/subscriptions" % pid,