feat: API 변화 저널과 outbox worker를 연결
입력 이벤트의 업무 변경, 성공 원장, revision 및 outbox를 한 transaction에서 커밋한다. 설문의 commit 전 Redis 발행을 제거하고 접속 점수용 private revision과 재시도·retention을 갖춘 dispatcher lifecycle을 추가한다.
This commit is contained in:
@@ -44,4 +44,5 @@ export interface DatabaseClient {
|
||||
vote: GamePrisma.VoteDelegate;
|
||||
inputEvent: GamePrisma.InputEventDelegate;
|
||||
turnDaemonLease: GamePrisma.TurnDaemonLeaseDelegate;
|
||||
readModelOutbox: GamePrisma.ReadModelOutboxDelegate;
|
||||
}
|
||||
|
||||
@@ -6,7 +6,9 @@ import {
|
||||
type ReadModelRevisionKey,
|
||||
} from '@sammo-ts/common';
|
||||
|
||||
import { GamePrisma } from './gamePrisma.js';
|
||||
import { GamePrisma, type GamePrismaClient } from './gamePrisma.js';
|
||||
|
||||
export type ReadModelJournalDatabase = Pick<GamePrismaClient, '$queryRaw'>;
|
||||
|
||||
interface ReadModelJournalWriteRow {
|
||||
domain: string;
|
||||
@@ -61,7 +63,7 @@ const assertWriteRows = (
|
||||
* that owns the domain mutation; this function never opens or commits one.
|
||||
*/
|
||||
export const writeReadModelChangeJournal = async (
|
||||
transaction: GamePrisma.TransactionClient,
|
||||
transaction: ReadModelJournalDatabase,
|
||||
candidates: Iterable<ReadModelRevisionKey>
|
||||
): Promise<ReadModelJournalWriteResult | null> => {
|
||||
const keys = normalizeReadModelRevisionKeys(candidates);
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user