feat: 다중 프로필 DB 부하 계측을 추가

production 턴 런타임의 lease, flush, outbox와 Redis 발행을 한 달 단위로 측정한다. nya와 pya 1분 프로필의 격리 fixture 및 현재 process·잠금 경계 문서를 함께 추가한다.
This commit is contained in:
2026-08-17 15:43:14 +00:00
parent 50e7d894e4
commit efb7be3cb9
9 changed files with 619 additions and 7 deletions
+22
View File
@@ -6,6 +6,10 @@ import test from 'node:test';
import { assertRuntimeMetadataFinalized, canonicalJson, expandWeightedOperations, loadTokens, validateLoadConfig } from '../src/config.js';
const samplePath = new URL('../config/300-users-900-npcs-5m.json', import.meta.url);
const oneMinuteProfilePaths = [
new URL('../config/nya-10-users-800-npcs-1m.json', import.meta.url),
new URL('../config/pya-10-users-800-npcs-1m.json', import.meta.url),
];
void test('the 300 viewer, 900 NPC, five-minute sample validates', async () => {
const config = validateLoadConfig(JSON.parse(await readFile(samplePath, 'utf8')));
@@ -18,6 +22,24 @@ void test('the 300 viewer, 900 NPC, five-minute sample validates', async () => {
assert.deepEqual(new Set(config.phases.map((phase) => phase.kind)), new Set(['idle', 'own', 'global', 'mixed']));
});
void test('nya and pya one-minute profiles use distinct database and Redis isolation', async () => {
const configs = await Promise.all(
oneMinuteProfilePaths.map(async (configPath) =>
validateLoadConfig(JSON.parse(await readFile(configPath, 'utf8')))
)
);
assert.deepEqual(
configs.map((config) => config.capacity),
[
{ authenticatedViewers: 10, npcGenerals: 800, humanGenerals: 10, turnIntervalMs: 60_000 },
{ authenticatedViewers: 10, npcGenerals: 800, humanGenerals: 10, turnIntervalMs: 60_000 },
]
);
assert.equal(new Set(configs.map((config) => config.isolation.postgresSchema)).size, 2);
assert.equal(new Set(configs.map((config) => config.isolation.redisDatabase)).size, 2);
assert.equal(new Set(configs.map((config) => config.isolation.profileName)).size, 2);
});
void test('validation rejects public, non-allowlisted, and mutating targets', async () => {
const raw = JSON.parse(await readFile(samplePath, 'utf8')) as Record<string, any>;
raw.target.publicProfile = true;