feat(api): POST /api/v1/aider/events HMAC webhook + Redis stream push

- Router layer: HTTP validation + HMAC-SHA256 signature verification
- Service layer: Redis stream push (aider_event_service.push_aider_batch_to_stream)
- leWOOOgo積木化遵循: Router → Service → Redis
- All 6 tests passing (signature validation, batch limits, edge cases)
This commit is contained in:
Your Name
2026-04-20 04:31:41 +08:00
parent 964427c5d4
commit cd894310dc
3 changed files with 203 additions and 1 deletions

View File

@@ -5,10 +5,12 @@
- 不重做 dedup — 既有 IncidentService.create_incident_from_signal 已有 3min fingerprint debounce
- 不做 pattern extract — Task A8 ai_router 會直接從 aider_event_repository 聚合
- 純函式為主,副作用(建 incident由 callerA7 processor job管理
- Redis stream 推送 (Task A6):轉接 Router 層
"""
from __future__ import annotations
import os
from typing import Any
from src.models.aider import AiderEventIn
from src.models.aider import AiderEventIn, AiderBatchIn
from src.utils.secret_redactor import redact
@@ -109,3 +111,25 @@ def _compact_desc(event_type: str, payload: dict) -> str:
f"duration={payload.get('duration_sec',0)}s "
f"tokens={payload.get('tokens_sent',0)}+{payload.get('tokens_received',0)}")
return str(payload)[:200]
# ---- Redis stream 推送 (Task A6) ----
async def push_aider_batch_to_stream(batch: AiderBatchIn) -> list[str]:
"""把 event batch 推到 Redis stream。回傳 stream ID 列表。"""
from src.core.redis_client import get_redis
stream_key = os.environ.get("AIDER_EVENTS_STREAM_KEY", "signals:aider:events")
r = get_redis()
ids = []
for ev in batch.events:
msg_id = await r.xadd(stream_key, {"payload": ev.model_dump_json()})
ids.append(_to_str(msg_id))
return ids
def _to_str(x) -> str:
"""轉成 str相容 bytes 和 str 回傳值)。"""
return x.decode() if isinstance(x, bytes) else str(x)