- POST /api/v1/open/affiliate-dash:验签 → 查任务(404 重试) → webhook_events 幂等闸门 → 状态同步 - migration 013:webhook_events(provider+event_id 唯一) - task-repo findAffiliateDashTaskByOrder(仿 feifei 同构 SQL) - notify-service:去重闸门在找到任务之后,任务未匹配不被 eventId 永久拦截 - typecheck + 212 测试通过;前置错误分支脚本验证通过
44 lines
1.2 KiB
TypeScript
44 lines
1.2 KiB
TypeScript
import { query } from '../db/client.js'
|
|
import type { JsonObject } from '../types/json.js'
|
|
import { nowIso } from '../utils/time.js'
|
|
|
|
/**
|
|
* 幂等写入一条 webhook 事件(provider + event_id 唯一)。
|
|
* 冲突时不做任何更新并返回 inserted=false —— 供回调去重闸门使用。
|
|
*/
|
|
export async function insertWebhookEventOnce(input: {
|
|
provider: string
|
|
eventId: string
|
|
eventType: string
|
|
taskId?: number | string | null
|
|
payload: JsonObject
|
|
processedAt?: string
|
|
}): Promise<{ inserted: boolean }> {
|
|
const processedAt = input.processedAt || nowIso()
|
|
const result = await query<{ id: number }>(
|
|
`
|
|
INSERT INTO webhook_events (
|
|
provider,
|
|
event_id,
|
|
event_type,
|
|
task_id,
|
|
payload,
|
|
processed_at,
|
|
created_at
|
|
) VALUES ($1, $2, $3, $4, $5::jsonb, $6, $6)
|
|
ON CONFLICT (provider, event_id) DO NOTHING
|
|
RETURNING id
|
|
`,
|
|
[
|
|
String(input.provider || '').trim(),
|
|
String(input.eventId || '').trim(),
|
|
String(input.eventType || '').trim(),
|
|
input.taskId == null ? null : Number(input.taskId),
|
|
JSON.stringify(input.payload || {}),
|
|
processedAt,
|
|
],
|
|
)
|
|
|
|
return { inserted: result.rows.length > 0 }
|
|
}
|