feat: API 변화 저널과 outbox worker를 연결

입력 이벤트의 업무 변경, 성공 원장, revision 및 outbox를 한 transaction에서 커밋한다. 설문의 commit 전 Redis 발행을 제거하고 접속 점수용 private revision과 재시도·retention을 갖춘 dispatcher lifecycle을 추가한다.
This commit is contained in:
2026-08-16 18:22:57 +00:00
parent b41b161e9c
commit f858ca43f4
15 changed files with 606 additions and 52 deletions
@@ -2,6 +2,10 @@ import { parseReadModelOutboxPayload, type ReadModelOutboxPayloadV1 } from '@sam
import { GamePrisma, type GamePrismaClient } from './gamePrisma.js';
export interface ReadModelOutboxDatabase extends Pick<GamePrismaClient, '$queryRaw'> {
readModelOutbox: GamePrisma.ReadModelOutboxDelegate;
}
export interface ClaimedReadModelOutbox {
id: bigint;
payload: unknown;
@@ -46,7 +50,7 @@ const retryDelayMs = (attempts: number, baseMs: number, maxMs: number): number =
};
export const claimReadModelOutboxBatch = async (
db: GamePrismaClient,
db: ReadModelOutboxDatabase,
options: Pick<ReadModelOutboxDispatchOptions, 'owner' | 'limit' | 'leaseMs'> & { now?: Date }
): Promise<ClaimedReadModelOutbox[]> => {
if (!options.owner.trim()) {
@@ -82,7 +86,7 @@ export const claimReadModelOutboxBatch = async (
};
export const markReadModelOutboxDelivered = async (
db: GamePrismaClient,
db: ReadModelOutboxDatabase,
input: { id: bigint; owner: string; deliveredAt?: Date }
): Promise<boolean> => {
const result = await db.readModelOutbox.updateMany({
@@ -98,7 +102,7 @@ export const markReadModelOutboxDelivered = async (
};
export const releaseReadModelOutbox = async (
db: GamePrismaClient,
db: ReadModelOutboxDatabase,
input: { id: bigint; owner: string; error: unknown; availableAt: Date }
): Promise<boolean> => {
const result = await db.readModelOutbox.updateMany({
@@ -114,7 +118,7 @@ export const releaseReadModelOutbox = async (
};
export const dispatchReadModelOutboxBatch = async (
db: GamePrismaClient,
db: ReadModelOutboxDatabase,
publish: (payload: ReadModelOutboxPayloadV1, outboxId: bigint) => Promise<void>,
options: ReadModelOutboxDispatchOptions
): Promise<ReadModelOutboxDispatchResult> => {
@@ -156,7 +160,7 @@ export const dispatchReadModelOutboxBatch = async (
};
export const pruneDeliveredReadModelOutbox = async (
db: GamePrismaClient,
db: ReadModelOutboxDatabase,
input: { deliveredBefore: Date; limit?: number }
): Promise<number> => {
const limit = normalizeLimit(input.limit);