3.9 KiB
id, status
| id | status |
|---|---|
| ac-0029 | active |
Ledger outbox instance ownership and lease fencing
Criterion
trex-core의 durable ledger outbox row는 enqueue 시점의 required non-empty instance_key를 immutable owner로 저장해야 하며, daemon·operator backfill·targeted processing을 포함한 모든 delivery 경로는 자기 instance의 row만 claim하고 처리해야 한다. Shared PostgreSQL에서 claim은 pending·retry-due·unclaimed 또는 lease-expired row를 원자적으로 선택해 worker별 bounded lease를 설정해야 하고, 성공·중복·retryable·conflict·permanent·dead-letter outcome은 해당 claim의 fencing 정보가 일치할 때만 반영해야 한다. 다른 instance, legacy instance_key IS NULL, 아직 유효한 foreign lease 또는 이미 새 worker가 reclaim한 row는 처리·상태 변경·성공 통계·ledger-skip resolution 없이 fail closed 해야 한다.
Claim owner가 crash하면 lease 만료 후 같은 instance의 다른 worker가 row를 reclaim할 수 있어야 한다. Outcome CAS가 0건이면 claim 상실로 명시적으로 처리하고 성공 outcome으로 보고해서는 안 된다. InMemory와 PostgreSQL outbox는 instance filtering, active lease exclusion, expiry recovery와 stale-claim rejection에서 같은 의미를 가져야 한다. Claim·outcome 관측 정보에는 instance_key, sanitized result/reason과 correlation identity만 허용하며 credential, account identifier, token, password, DSN, provider payload 또는 exception 원문을 로그·metric·alert에 포함해서는 안 된다.
Verification
- 격리 조건: 서로 다른
instance_key의 daemon/writer 두 개가 한 PostgreSQL을 공유할 때 각 writer는 자기 row만 claim·전송·집계한다.list_pending,pending_cash_delta, batch claim과 correlation-targeted claim 모두 foreign row와instance_key IS NULLlegacy row를 제외한다. 누락·빈 instance key로 outbox 또는 writer를 생성하면 외부 연결이나 row 생성 전에 거부된다. - lease 조건: worker A가 claim한 row는 lease 동안 worker B가 claim하지 못한다. A가 outcome을 기록하면 lease가 해제되고 terminal 또는 retry 상태가 정확히 저장된다. A가 crash한 경우 expiry 전에는 B가 claim하지 못하고 expiry 뒤에는 B가 reclaim할 수 있다. Reclaim 뒤 A의 stale outcome은 typed claim-lost 결과로 거부되며 B의 row 상태, outcome, attempt count, next retry와 lease를 변경하지 않는다.
- outcome 조건: adapter의 신규 성공과
DUPLICATE_OK, retryable, conflict, permanent 및 dead-letter 모든 분기는 claim fencing을 전달한다. CAS 실패 시 completion/retry counter, 성공 로그, snapshot write-back 이후의 ledger-skip resolution을 실행하지 않는다. Adapter duplicate는 row를completed/duplicate_completed로 만들고 lease를 즉시 해제하여 재전송되지 않는다. - InMemory parity: 두 번의 동시 claim에서 첫 claim만 성공하고 active lease row는 pending scan에서 제외된다. clock을 이동하면 expiry recovery가 가능하며 이전 claim token으로 outcome을 기록할 수 없다. Instance filter와 targeted processing의 fail-closed 동작이 PostgreSQL과 같다.
- 보안 조건: exception에 credential·account·token·password·DSN·provider payload를 식별하는 sentinel을 넣어 claim 실패, retry, permanent, dead-letter와 write-back 오류를 실행해도 rendered log, metric key/value와 alert에 sentinel 또는 exception 원문이 나타나지 않는다.
- migration 및 회귀: migration 번호는 저장소에서 유일하고 기존 row를 자동 귀속시키지 않으며
instance_key IS NULL로 격리한다. 빈 DB와 기존 schema 모두에서 migration apply/replay, PostgreSQL claim round-trip, restart/expiry 회수, daemon·CLI wiring을 검증한다. 전체 repository test, Ruff, compileall, ProofLine validation과git diff --check를 실행한다.