fix: retain realtime work through draining
R-02: add an OPEN/DRAINING/CLOSED lifecycle orthogonal to freshness. Effect and recovery authorities are now awaited under a deadline: on expiry the commit capability is revoked and the work aborted, the caller gets a bounded non-retryable IDLE_TIMEOUT, and the underlying task is retained rather than dropped. A draining stream refuses new events and recovery, and close() returns a Promise that succeeds only once every retained task actually settled, reporting IDLE_TIMEOUT otherwise. R-03: a handoff fail-close moves active, probe, quiescing and transition leases into a retired-writer set before clearing their references, and close() waits on current and retired writers together, so an abandoned non-cooperative writer can no longer make teardown report a false success. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
c9e820aed5
commit
2f29ccbf1a
@@ -11,6 +11,26 @@
|
||||
첫 제품 stream/Web Push를 선택할 때, 또는 backend replay/hosting/provider
|
||||
protocol이 바뀔 때
|
||||
|
||||
|
||||
## 스트림 lifecycle은 freshness와 직교한다 (R-02, R-03)
|
||||
|
||||
`RealtimeStreamLifecycle = OPEN | DRAINING | CLOSED`는 freshness
|
||||
(`UNKNOWN/CURRENT/STALE/RESYNCING`)와 별개다.
|
||||
|
||||
- effect/recovery deadline에 도달하면 commit capability를 즉시 영구 무효화하고
|
||||
abort한다. caller에는 bounded `IDLE_TIMEOUT`(non-retryable, operation
|
||||
`APPLY`/`RECOVER`)을 반환하되 **실제 task는 버리지 않고 retain**한다.
|
||||
- retain된 task가 하나라도 있으면 stream은 `DRAINING`이고 새 event/recovery
|
||||
admission을 거절한다. 실제 settlement가 일어나야 `STALE`로 돌아가
|
||||
authoritative recovery를 요구하거나, close 요청이면 `CLOSED`가 된다.
|
||||
- `close()`는 `Promise<RealtimeResult<void>>`다. 모든 retain task가 실제로
|
||||
settle해야 success이고, drain bound를 넘기면 `IDLE_TIMEOUT/CLOSE`를 반환하며
|
||||
stream은 계속 `DRAINING`이다. teardown success가 곧 quiescence다.
|
||||
- LIVE↔POLL overflow fail-close는 active/probe/quiescing/transition lease를
|
||||
모두 abort한 뒤 **retired writer set**으로 옮기고 나서 reference를 지운다.
|
||||
`close()`는 current와 retired를 dedupe해 함께 기다리므로, 버려진
|
||||
non-cooperative writer가 아직 실행 중인데 close가 성공을 보고할 수 없다.
|
||||
|
||||
## 배경
|
||||
|
||||
현재 optional recipe catalog는 realtime capability에
|
||||
|
||||
@@ -34,6 +34,16 @@ capability가 설치됐거나 production-ready라는 뜻이 아니다.
|
||||
[Frontend ports, adapters, and boundaries](./frontend-ports-adapters-and-boundaries.md)
|
||||
를 따른다.
|
||||
|
||||
|
||||
## Bounded task lease와 DRAINING (R-02, R-03)
|
||||
|
||||
non-cooperative effect/recovery authority 하나가 stream tail 전체를 영구
|
||||
wedge하지 못하도록, common coordinator는 각 task를 deadline으로 감싼다. deadline
|
||||
초과 시 commit capability는 즉시 취소되지만 task 자체는 `retainedTasks`에 남아
|
||||
stream을 `DRAINING`으로 유지한다. `close()`는 이 retain 집합이 실제로 settle해야
|
||||
성공을 반환한다. handoff coordinator도 같은 원칙으로 fail-close된 writer를
|
||||
`retiredWriters`에 보존한다.
|
||||
|
||||
## 0. 현재 상태와 목표 delta
|
||||
|
||||
이 문서에서 설계 승인, reference source 존재, production 조합과 target browser의
|
||||
|
||||
@@ -105,8 +105,8 @@ Rollout state starts at `NOT_STARTED`; documented-unimplemented items start at
|
||||
| ID | Activation | Red test command | Fix commit/PR | Rollout state | Rollback trigger | Evidence |
|
||||
| --- | --- | --- | --- | --- | --- | --- |
|
||||
| R-01 | Browser RPC `AVAILABLE_NOT_COMPOSED` | `corepack pnpm exec vitest run tests/unit/browser-rpc/browser-rpc-runtime.test.ts` | — | `NOT_STARTED` | stream lease deadlock | — |
|
||||
| R-02 | Realtime `NOT_SELECTED` | `corepack pnpm exec vitest run tests/unit/realtime/stream-coordinator.test.ts` | — | `NOT_STARTED` | stream stuck in `DRAINING` | — |
|
||||
| R-03 | Realtime `NOT_SELECTED` | `corepack pnpm exec vitest run tests/unit/realtime/live-poll-handoff-coordinator.test.ts` | — | `NOT_STARTED` | retired-writer set growth | — |
|
||||
| R-02 | Realtime `NOT_SELECTED` | `corepack pnpm exec vitest run tests/unit/realtime/stream-coordinator.test.ts` | `fix: retain realtime work through draining` | `FIXED_NOT_RELEASED` | stream stuck in `DRAINING` | Red never-settling effect and recovery → green 27/27; `close()` returns `IDLE_TIMEOUT` while a task is retained and success only after actual settlement |
|
||||
| R-03 | Realtime `NOT_SELECTED` | `corepack pnpm exec vitest run tests/unit/realtime/live-poll-handoff-coordinator.test.ts` | `fix: retain realtime work through draining` | `FIXED_NOT_RELEASED` | retired-writer set growth | Red overflow fail-close then `close()` → green 11/11; retired writers are waited on and only removed once actually quiesced |
|
||||
| R-04 | Browser RPC `AVAILABLE_NOT_COMPOSED` | `corepack pnpm exec vitest run tests/unit/browser-rpc/browser-rpc-contract.test.ts` | — | `NOT_STARTED` | binding install rejection | — |
|
||||
| R-05 | WebSocket protocol codec | `corepack pnpm exec vitest run tests/unit/realtime/websocket-protocol.test.ts` | — | `NOT_STARTED` | frame rejection regression | — |
|
||||
| R-06 | Browser RPC `AVAILABLE_NOT_COMPOSED` | `corepack pnpm exec vitest run tests/unit/browser-rpc/browser-rpc-runtime.test.ts` | — | `NOT_STARTED` | closed-failure taxonomy drift | — |
|
||||
|
||||
Reference in New Issue
Block a user