감사 상세를 무손실 압축하고 이전 기수 정리 처리량을 개선한다
This commit is contained in:
1 parent
da79013226
commit
078b9aa205
23 files changed
+504
-95
No files matched your search
@@ -2,7 +2,12 @@ import { afterAll, beforeAll, expect, it } from 'vitest';
|
||||
import fastify from 'fastify';
|
||||
import { fastifyTRPCPlugin } from '@trpc/server/adapters/fastify';
|
||||
import { asRecord } from '@sammo-ts/common';
|
||||
import { createGamePostgresConnector, createRedisConnector, GamePrisma } from '@sammo-ts/infra';
|
||||
import {
|
||||
decodeAuditDecisionSteps,
|
||||
createGamePostgresConnector,
|
||||
createRedisConnector,
|
||||
GamePrisma,
|
||||
} from '@sammo-ts/infra';
|
||||
import { createTurnDaemonRuntime, seedScenarioToDatabase, type TurnDaemonRuntime } from '@sammo-ts/game-engine';
|
||||
import { appRouter } from '../src/router.js';
|
||||
import { DatabaseTurnDaemonTransport } from '../src/daemon/databaseTransport.js';
|
||||
@@ -255,12 +260,10 @@ integration(
|
||||
include: { chunks: { orderBy: { ordinal: 'asc' } } },
|
||||
});
|
||||
const procedures = nationDecision.chunks.flatMap((chunk) =>
|
||||
Array.isArray(chunk.steps)
|
||||
? chunk.steps
|
||||
.map(asRecord)
|
||||
.filter((step) => step.kind === 'PROCEDURE_START')
|
||||
.map((step) => step.procedure)
|
||||
: []
|
||||
decodeAuditDecisionSteps(chunk.steps)
|
||||
.map(asRecord)
|
||||
.filter((step) => step.kind === 'PROCEDURE_START')
|
||||
.map((step) => step.procedure)
|
||||
);
|
||||
expect(procedures).toEqual(['NPC포상']);
|
||||
expect(configuration(await call('getPolicy', {}))).toEqual(configuration(withoutRecruitment));
|
||||
|
||||
@@ -45,6 +45,28 @@ const createFixture = (rows: readonly object[]) => {
|
||||
};
|
||||
|
||||
describe('ReadModelOutboxWorker', () => {
|
||||
it('drains more than one full retention batch rather than leaving a permanent 100-per-minute backlog', async () => {
|
||||
let now = new Date('2026-11-09T00:00:00Z');
|
||||
const fixture = createFixture([]);
|
||||
fixture.queryRaw
|
||||
.mockReset()
|
||||
.mockResolvedValueOnce([])
|
||||
.mockResolvedValueOnce([{ id: 1n }, { id: 2n }])
|
||||
.mockResolvedValueOnce([{ id: 3n }, { id: 4n }])
|
||||
.mockResolvedValueOnce([]);
|
||||
const worker = new ReadModelOutboxWorker(fixture.db, fixture.redis, 'che:default', {
|
||||
intervalMs: 60000,
|
||||
pruneLimit: 2,
|
||||
now: () => now,
|
||||
});
|
||||
now = new Date('2026-11-09T00:01:00Z');
|
||||
worker.start();
|
||||
await vi.waitFor(() => expect(fixture.queryRaw).toHaveBeenCalledTimes(4));
|
||||
await worker.stop();
|
||||
const query = fixture.queryRaw.mock.calls[1]?.[0] as { sql: string };
|
||||
expect(query.sql).toContain('FOR UPDATE SKIP LOCKED');
|
||||
expect(query.sql).toContain('ORDER BY "delivered_at", "available_at", "id"');
|
||||
});
|
||||
it('publishes a survey-style global front-status invalidation without a turn daemon', async () => {
|
||||
const fixture = createFixture([{ id: 10n, payload: payload('front.global'), attempts: 1 }]);
|
||||
const worker = new ReadModelOutboxWorker(fixture.db, fixture.redis, 'che:default', {
|
||||
|
||||
@@ -13,6 +13,7 @@ import { afterAll, beforeAll, beforeEach, describe, expect, it } from 'vitest';
|
||||
import { encryptGameSessionToken, type GameSessionTokenPayload } from '@sammo-ts/common/auth/gameToken';
|
||||
import {
|
||||
createGamePostgresConnector,
|
||||
encodeAuditDecisionSteps,
|
||||
GamePrisma,
|
||||
hashAuditDiplomacyDocument,
|
||||
createRedisConnector,
|
||||
@@ -2345,50 +2346,52 @@ integration('game API security over HTTP transport', () => {
|
||||
{
|
||||
decisionId: decisionIds[0]!,
|
||||
ordinal: 0,
|
||||
steps: Array.from({ length: 128 }, (_, sequence) =>
|
||||
sequence === 127
|
||||
? {
|
||||
...step,
|
||||
sequence,
|
||||
kind: 'DECISION_START',
|
||||
reservedAction: '휴식',
|
||||
effectivePolicy: {
|
||||
schemaVersion: 1,
|
||||
general: { priority: ['징병'], flags: { 징병: true, 출병: false } },
|
||||
nation: {
|
||||
priority: ['천도'],
|
||||
flags: { 천도: true },
|
||||
values: {
|
||||
reqNationGold: 4321,
|
||||
reqNationRice: 100,
|
||||
reqHumanWarUrgentGold: 100,
|
||||
reqHumanWarUrgentRice: 100,
|
||||
reqHumanWarRecommandGold: 100,
|
||||
reqHumanWarRecommandRice: 100,
|
||||
reqHumanDevelGold: 100,
|
||||
reqHumanDevelRice: 100,
|
||||
reqNpcWarGold: 100,
|
||||
reqNpcWarRice: 100,
|
||||
reqNpcDevelGold: 100,
|
||||
reqNpcDevelRice: 100,
|
||||
minimumResourceActionAmount: 100,
|
||||
maximumResourceActionAmount: 100,
|
||||
minNpcWarLeadership: 100,
|
||||
minWarCrew: 100,
|
||||
minNpcRecruitCityPopulation: 100,
|
||||
safeRecruitCityPopulationRatio: 100,
|
||||
properWarTrainAtmos: 100,
|
||||
cureThreshold: 100,
|
||||
steps: encodeAuditDecisionSteps(
|
||||
Array.from({ length: 128 }, (_, sequence) =>
|
||||
sequence === 127
|
||||
? {
|
||||
...step,
|
||||
sequence,
|
||||
kind: 'DECISION_START',
|
||||
reservedAction: '휴식',
|
||||
effectivePolicy: {
|
||||
schemaVersion: 1,
|
||||
general: { priority: ['징병'], flags: { 징병: true, 출병: false } },
|
||||
nation: {
|
||||
priority: ['천도'],
|
||||
flags: { 천도: true },
|
||||
values: {
|
||||
reqNationGold: 4321,
|
||||
reqNationRice: 100,
|
||||
reqHumanWarUrgentGold: 100,
|
||||
reqHumanWarUrgentRice: 100,
|
||||
reqHumanWarRecommandGold: 100,
|
||||
reqHumanWarRecommandRice: 100,
|
||||
reqHumanDevelGold: 100,
|
||||
reqHumanDevelRice: 100,
|
||||
reqNpcWarGold: 100,
|
||||
reqNpcWarRice: 100,
|
||||
reqNpcDevelGold: 100,
|
||||
reqNpcDevelRice: 100,
|
||||
minimumResourceActionAmount: 100,
|
||||
maximumResourceActionAmount: 100,
|
||||
minNpcWarLeadership: 100,
|
||||
minWarCrew: 100,
|
||||
minNpcRecruitCityPopulation: 100,
|
||||
safeRecruitCityPopulationRatio: 100,
|
||||
properWarTrainAtmos: 100,
|
||||
cureThreshold: 100,
|
||||
},
|
||||
combatForce: { '1': [2, 3] },
|
||||
supportForce: [4],
|
||||
developForce: [5],
|
||||
secret: 'decision-secret',
|
||||
},
|
||||
combatForce: { '1': [2, 3] },
|
||||
supportForce: [4],
|
||||
developForce: [5],
|
||||
secret: 'decision-secret',
|
||||
},
|
||||
secret: 'decision-secret',
|
||||
},
|
||||
}
|
||||
: { ...step, sequence }
|
||||
}
|
||||
: { ...step, sequence }
|
||||
)
|
||||
),
|
||||
},
|
||||
{
|
||||
|
||||
Reference in new issue
Block a user