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
+10
View File
@@ -30,6 +30,7 @@ import { createAdminProfileIconResetFlushHandler } from './services/accountIconS
import { AccountIconResetReconciler } from './services/accountIconResetReconciler.js';
import { createBestEffortResourceCloser } from './services/bestEffortResourceCloser.js';
import { RemoteContentImageStore } from './services/remoteContentImageStore.js';
import { ReadModelOutboxWorker } from './realtime/outboxWorker.js';
const extractBearerToken = (value: string | string[] | undefined): string | null => {
if (!value) {
@@ -140,9 +141,16 @@ export const createGameApiServer = async () => {
throw error;
}
const realtimeHub = new RedisRealtimeEventHub(realtimeSubscriberClient, buildGameEventChannel(config.profileName));
const readModelOutboxWorker = new ReadModelOutboxWorker(postgres.prisma, redis.client, config.profileName, {
onError: (error) => app.log.error({ err: error }, 'read-model outbox dispatch failed'),
});
let flushSubscriberStarted = false;
let realtimeHubStarted = false;
const closeResources = createBestEffortResourceCloser([
{
name: 'read-model-outbox-worker',
run: () => readModelOutboxWorker.stop(),
},
{
name: 'account-icon-reset-reconciler',
run: () => accountIconResetReconciler.stop(),
@@ -220,6 +228,7 @@ export const createGameApiServer = async () => {
gameTokenSecret: config.gameTokenSecret,
accountIconSource,
profileStatusSource,
readModelOutbox: readModelOutboxWorker,
});
},
},
@@ -334,6 +343,7 @@ export const createGameApiServer = async () => {
realtimeHubStarted = true;
await flushSubscriber.start();
flushSubscriberStarted = true;
readModelOutboxWorker.start();
accountIconResetReconciler.start();
} catch (error) {
await closeResources();