Skip to content

Commit cfc41d3

Browse files
committed
docs: clarify ingress atomicity and subject scope
1 parent 2a32844 commit cfc41d3

1 file changed

Lines changed: 28 additions & 6 deletions

File tree

docs/improve-github-app/README.md

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -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
2932
issue:{org}/{repo}#{number}
3033
pr:{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

4142
worker가 이 값을 계산해 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
9599
stream: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

Comments
 (0)