@@ -21,21 +21,22 @@ dedupKey := "dedup:delivery:" + deliveryID
2121
2222### 1-2. subject
2323
24- ` subject ` : 하나의 채널톡 루트메시지와 채널톡 스레드 상태를 공유하는 canonical 처리 단위.
24+ ` subject ` : Phase 1/2에서 하나의 채널톡 루트메시지와 채널톡 스레드 상태를 공유하는 canonical 처리 단위.
2525
26- canonical subject는 아래 세 종류로 고정.
26+ 이 문서의 ` subject/root/anchor ` 모델은 issue / PR 계열에만 적용한다.
27+ release event는 현재 구현처럼 standalone group message로만 dispatch하며, Phase 1/2의 shared root state / Anchor recovery 범위에 포함하지 않는다.
28+
29+ canonical subject는 아래 두 종류로 고정.
2730
2831``` text
2932issue:{org}/{repo}#{number}
3033pr:{org}/{repo}#{number}
31- release:{org}/{repo}:{tag}
3234```
3335
3436- issue event -> ` issue:{org}/{repo}#{number} `
3537- pull_request 계열 event -> ` pr:{org}/{repo}#{number} `
3638- issue_comment on issue -> ` issue:{org}/{repo}#{number} `
3739- issue_comment on pull request -> ` pr:{org}/{repo}#{number} `
38- - release event -> ` release:{org}/{repo}:{tag} `
3940- status/check_run -> merged된 PR association hit 시 기존 ` pr:{org}/{repo}#{number} ` subject에만 매핑
4041
4142worker가 이 값을 계산해 lock/state key 생성.
@@ -57,7 +58,7 @@ association miss 시 packet은 drop/skip 한다.
5758## 2. Goals
5859
5960- delivery dedup을 도입해 같은 webhook delivery의 중복 처리를 막는다.
60- - subject 단위 lock/shared state를 도입해 canonical root를 한 번만 정한다.
61+ - issue / PR subject 단위 lock/shared state를 도입해 canonical root를 한 번만 정한다.
6162- out-of-order event를 pre-root queue와 lazy rebuild로 흡수한다.
6263- partial failure after root write 상황에서도 state/Anchor 기반으로 resume 가능하게 만든다.
6364- ` status ` / ` check_run ` 은 기존 merged PR thread에만 연결되게 유지한다.
@@ -68,12 +69,15 @@ association miss 시 packet은 drop/skip 한다.
6869- downstream thread write 성공 후 ack/state 저장 전 crash로 인한 duplicate thread message는 Phase 1/2 범위에서 제거하지 않는다.
6970- late ` opened ` 를 위해 root merge나 root replacement를 하지 않는다.
7071- ` status ` / ` check_run ` 용 독립 subject나 fallback root를 만들지 않는다.
72+ - release event를 Phase 1/2의 subject/root/anchor state machine에 포함하지 않는다.
7173- ingress stream을 장기 source-of-truth 저장소로 쓰지 않는다.
7274
7375## 4. Processing Semantics
7476
7577- ingress stream consumption과 worker retry 모델은 ` at least once ` 를 전제로 한다.
7678- ` dedup:delivery:{deliveryID} ` 는 동일 delivery의 중복 진입을 줄이기 위한 guard이지, 모든 downstream side effect의 exactly-once를 의미하지 않는다.
79+ - ingress는 ` dedup check + stream append + dedup record ` 를 ValKey Lua/function 한 번으로 원자적으로 수행한다.
80+ - ingress는 atomic enqueue 결과를 받기 전에는 delivery를 성공 처리하지 않는다. atomic step 실패 시 request는 실패로 남기고 GitHub redelivery에 의존한다.
7781- subject root selection은 strong invariant로 본다. 즉 ` rootMessageId ` 가 한 번 저장되면 그 root가 canonical root다.
7882- pre-root queue는 bounded hold 용도다. packet은 짧은 window 동안만 유지하고, timeout 이후에는 ` waiting_root_expired ` 와 lazy rebuild로 복구를 시도한다.
7983- downstream dispatch는 best-effort retry 대상이다. worker가 downstream thread write 성공 후 ack/state 저장 전에 중단되면 동일 delivery의 thread message가 중복 관찰될 수 있다.
@@ -89,7 +93,7 @@ Schema는 phase별 책임과 필요한 키만 남김.
8993
9094``` text
9195# delivery dedup
92- dedup:delivery:{deliveryID} -> "1" TTL 7d
96+ dedup:delivery:{deliveryID} -> "{streamEntryID}" TTL 7d
9397
9498# ingress queue
9599stream:github-events -> WebhookPacket retain 1h, trim by age/size
@@ -111,10 +115,28 @@ pre-root:buffered-delivery:{subjectKey} -> Set(deliveryID) TTL 30s
111115
112116- ` dedup:delivery:{deliveryID} `
113117 - 같은 delivery를 두 번 처리하지 않기 위한 idempotency key
118+ - value는 ` "1" ` 고정값이 아니라 ingress가 enqueue에 성공했을 때 받은 ` streamEntryID `
119+ - duplicate redelivery는 key 존재만으로 판별하고, 저장된 ` streamEntryID ` 는 운영 디버깅/추적에 사용
114120- ` stream:github-events `
115121 - ingress가 raw webhook packet을 적재하는 단일 stream
116122 - ` PacketQueue ` 의 ValKey Streams backend
117123 - source-of-truth 저장소가 아니라 짧은 transport backlog이므로 최근 1시간만 보관
124+
125+ Ingress write contract:
126+
127+ ``` text
128+ atomicEnqueue(packet):
129+ if EXISTS dedup:delivery:{deliveryID}:
130+ return duplicate
131+
132+ streamEntryID = XADD stream:github-events * packet
133+ SET dedup:delivery:{deliveryID} streamEntryID EX 7d
134+ return enqueued(streamEntryID)
135+ ```
136+
137+ - 위 세 단계는 ingress에서 분리 수행하지 않고 ValKey Lua/function 한 번으로 실행한다.
138+ - ` SET dedup ` 이 먼저 성공하고 ` XADD ` 전에 중단되는 경우, 혹은 ` XADD ` 후 ` SET dedup ` 전에 중단되는 경우를 허용하지 않는다.
139+ - 즉 ingress crash/retry에 대해 ` deliveryID ` 당 ` stream:github-events ` enqueue는 0회 또는 1회만 관찰되게 만든다.
118140- ` lock:subject:{subjectKey} `
119141 - 같은 subject를 동시에 두 worker가 처리하지 못하게 하는 distributed lock
120142- ` subject:{subjectKey} `
0 commit comments