When implementing cursor-based dedup/caching for event dispatch, ensure the dedup “key space” matches the real uniqueness of what you’re trying to prevent:
Practical template:
// 1) Dedup key must change when the triggering content changes.
const notifKey = `${notification.id}|${notification.updated_at}`; // not just notification.id
if (this.isDispatched(this.cursor.dispatchedNotifications, notifKey)) return;
// 2) Dispatch
await this.handleInbound(envelope);
// 3) Persist dedup keys for the exact items you dispatched
this.recordDispatched('dispatchedComments', dedupKey);
this.recordDispatched('dispatchedBodies', `${chatId}|${threadId}`);
this.recordDispatched('dispatchedEvents', triggerKey);
// 4) When re-discovering triggers, include both bounds
const event = events.findLast((candidate) => {
const t = candidate.created_at;
return t && t <= ctx.maxUpdatedAt && t > ctx.windowSince;
});
Acceptance checklist for reviews: 1) Every dispatch path has a corresponding, persisted dedup record (comments/bodies/events) on success. 2) Dedup keys include all dimensions needed to distinguish distinct “things to dispatch.” 3) Trigger search uses the same window bounds as the comment/body fetch logic. 4) Cursor trimming covers every dedup bucket you rely on. 5) HTTP read/caching headers are only applied on non-error response branches (or explicitly proven safe).
Enter the URL of a public GitHub repository