feat: 서버 준비 전에 감사 초기 상태와 정책 기준을 저장
This commit is contained in:
@@ -74,6 +74,7 @@ import { prepareRealtimeRecovery } from './prepareRealtimeRecovery.js';
|
||||
|
||||
export interface DatabaseTurnHooks {
|
||||
hooks: TurnDaemonHooks;
|
||||
flushChanges(): Promise<void>;
|
||||
takeCommittedReadModelChanges(): RealtimeReadModelChanges | null;
|
||||
takeCommittedReadModelChangeReceipt(): CommittedReadModelChangeReceipt | null;
|
||||
close(): Promise<void>;
|
||||
@@ -2078,12 +2079,13 @@ export const createDatabaseTurnHooks = async (
|
||||
};
|
||||
};
|
||||
|
||||
const flushChanges = async (): Promise<void> => {
|
||||
const committed = await persistChanges();
|
||||
committed.acknowledge();
|
||||
enqueueCommittedReceipt(committed.readModelChanges, committed.journalWrite);
|
||||
};
|
||||
const hooks: TurnDaemonHooks = {
|
||||
flushChanges: async () => {
|
||||
const committed = await persistChanges();
|
||||
committed.acknowledge();
|
||||
enqueueCommittedReceipt(committed.readModelChanges, committed.journalWrite);
|
||||
},
|
||||
flushChanges,
|
||||
commitCommand: async (requestId, result) => {
|
||||
const committed = await persistChanges(undefined, { requestId, result });
|
||||
committed.acknowledge();
|
||||
@@ -2127,6 +2129,7 @@ export const createDatabaseTurnHooks = async (
|
||||
|
||||
return {
|
||||
hooks,
|
||||
flushChanges,
|
||||
takeCommittedReadModelChanges: () => {
|
||||
return takeCommittedReceipt()?.changes ?? null;
|
||||
},
|
||||
|
||||
@@ -1377,6 +1377,10 @@ export class InMemoryTurnWorld {
|
||||
this.pendingAuditPolicies.push(structuredClone(policy));
|
||||
}
|
||||
|
||||
hasPendingAuditRecords(): boolean {
|
||||
return this.pendingAuditPolicies.length > 0 || this.pendingAuditMonths.length > 0;
|
||||
}
|
||||
|
||||
queueAuditMonth(snapshot: PendingAuditMonth): void {
|
||||
this.pendingAuditMonths.push(structuredClone(snapshot));
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { initializeAuditPolicies } from '../playAudit/policy.js';
|
||||
import { startAuditRetentionWorker } from '../playAudit/retentionWorker.js';
|
||||
import { createPlayAuditHandler } from '../playAudit/collection.js';
|
||||
import { createPlayAuditHandler, initializeAuditCollection } from '../playAudit/collection.js';
|
||||
import { randomUUID } from 'node:crypto';
|
||||
import { createRuntimePauseGate } from './runtimePauseGate.js';
|
||||
|
||||
@@ -804,7 +804,10 @@ const createTurnDaemonRuntimeWithLease = async (
|
||||
};
|
||||
const world = new InMemoryTurnWorld(resolvedState, snapshot, worldOptions);
|
||||
worldRef = world;
|
||||
initializeAuditPolicies(world);
|
||||
if (!databaseFlushEnabled) {
|
||||
initializeAuditPolicies(world);
|
||||
initializeAuditCollection(world, new Date(clock.nowMs()));
|
||||
}
|
||||
|
||||
const stateManager = new EngineStateManager();
|
||||
stateManager.register('world', {
|
||||
@@ -923,6 +926,14 @@ const createTurnDaemonRuntimeWithLease = async (
|
||||
});
|
||||
try {
|
||||
await dbHooks.prepareRealtimeRecovery({ paused: await gatewayGate?.shouldPause() });
|
||||
// 복구된 clock에서 기준을 고정하고 readiness 공개 전에 원자적으로 저장한다.
|
||||
// 명령 없는 PREOPEN도 기록하며 input_event나 게임 RNG를 만들지 않는다.
|
||||
initializeAuditPolicies(world);
|
||||
initializeAuditCollection(world, new Date(clock.nowMs()));
|
||||
if (world.hasPendingAuditRecords()) {
|
||||
await dbHooks.flushChanges();
|
||||
dbHooks.takeCommittedReadModelChangeReceipt();
|
||||
}
|
||||
} catch (error) {
|
||||
await Promise.allSettled([
|
||||
dbHooks.close(),
|
||||
|
||||
Reference in New Issue
Block a user