Pool Plutonium keys by game for launches and autoscaling

This commit is contained in:
2026-10-07 11:24:53 -04:00
parent 56e5a2d06d
commit ec45371478
47 changed files with 956 additions and 305 deletions
+11 -9
View File
@@ -10,7 +10,7 @@ async function setup() {
await prepareNativeHost();
const { db } = await import('../../src/lib/server/db/index.js');
const scaling = await import('../../src/lib/server/autoscaling/index.js');
for (const n of [3, 8]) db().prepare('INSERT INTO server_keys(server_id,pluto_key) VALUES(?,?)').run(`t6_zombie_town_${n}`, `key-${n}`);
for (const n of [3, 8]) db().prepare("INSERT INTO server_keys(id,game,pluto_key) VALUES(?,'t6',?)").run(`key-${n}`, `key-${n}`);
const saved = scaling.saveScaling(settings, undefined, undefined, scaling.previewScaling(settings).token);
return { db, scaling, saved };
}
@@ -21,7 +21,7 @@ it('admits one durable keyed create and reuses it across ticks and restart', asy
await Promise.all([scaling.runAutoscaling(), scaling.runAutoscaling()]);
const { closeDb } = await import('../../src/lib/server/db/index.js'); closeDb();
await scaling.runAutoscaling();
expect(db().prepare('SELECT server,state FROM server_deployments WHERE action=\'create\'').all()).toEqual([{ server: 't6_zombie_town_3', state: 'queued' }]);
expect(db().prepare('SELECT server,state FROM server_deployments WHERE action=\'create\'').all()).toEqual([{ server: 't6_zombie_town_1', state: 'queued' }]);
expect(db().prepare('SELECT COUNT(*) AS n FROM autoscaling_decisions WHERE resolved=0').get()).toEqual({ n: 1 });
const { operation_id: id } = db().prepare('SELECT operation_id FROM autoscaling_decisions WHERE resolved=0').get() as { operation_id: string };
const { scalingAdmission } = await import('../../src/lib/server/autoscaling/admission.js');
@@ -30,16 +30,19 @@ it('admits one durable keyed create and reuses it across ticks and restart', asy
expect(getDeployment(id)?.sources).toContainEqual(expect.objectContaining({ kind: 'autoscaling', href: `/autoscaling#${saved.id}` }));
});
it('requires key coverage and withdraws an unsubmitted create when the policy pauses', async () => {
it('withdraws an unsubmitted create and returns its game key when the policy pauses', async () => {
const { db, scaling, saved } = await setup();
await scaling.runAutoscaling();
const off = { ...settings, mode: 'off' };
scaling.saveScaling(off, saved.id, saved.revision, scaling.previewScaling(off, saved.id, saved.revision).token);
expect(db().prepare("SELECT state FROM server_deployments WHERE action='create'").get()).toEqual({ state: 'cancelled' });
expect(db().prepare('SELECT owns_map FROM autoscaling_policies').get()).toEqual({ owns_map: 0 });
db().prepare("DELETE FROM server_keys WHERE server_id='t6_zombie_town_8'").run();
expect(db().prepare('SELECT COUNT(*) AS n FROM server_key_leases').get()).toEqual({ n: 0 });
db().prepare('DELETE FROM server_keys').run();
const current = scaling.getScalingPolicy(saved.id)!;
expect(scaling.previewScaling(settings, saved.id, current.revision).blockers.join(' ')).toContain('Save keys');
const preview = scaling.previewScaling(settings, saved.id, current.revision);
expect(preview.blockers).toEqual([]);
expect(preview.snapshot.keyPool).toEqual({ total: 0, available: 0 });
});
it('blocks manual lifecycle and collection creation, including stale previews', async () => {
@@ -78,7 +81,7 @@ it('exact matching cannot remove an owned map absent from the collection', async
const { db } = await import('../../src/lib/server/db/index.js');
const at = new Date().toISOString();
db().prepare("INSERT INTO servers(name,game,map,map_slug,container_state,container_checked_at,last_seen_at,last_players) VALUES(?,'t6','zm_transit','town','running',?,?,0)").run(town, at, at);
for (const n of [1, 2]) db().prepare('INSERT INTO server_keys(server_id,pluto_key) VALUES(?,?)').run(`t6_zombie_town_${n}`, `key-${n}`);
for (const n of [1, 2]) db().prepare("INSERT INTO server_keys(id,game,pluto_key) VALUES(?,'t6',?)").run(`key-${n}`, `key-${n}`);
const scaling = await import('../../src/lib/server/autoscaling/index.js');
scaling.saveScaling(settings, undefined, undefined, scaling.previewScaling(settings).token);
const { saveBlueprint } = await import('../../src/lib/server/fleet/launch-recipes.js');
@@ -90,13 +93,12 @@ it('exact matching cannot remove an owned map absent from the collection', async
expect(() => queueCollection({ previewId: preview.id })).toThrow('Autoscaling');
});
it('rechecks evidence and global pause before dispatch', async () => {
it('honors global pause before dispatch while recognizing its own reserved key', async () => {
const { db, scaling } = await setup();
await scaling.runAutoscaling();
const { operation_id: id } = db().prepare('SELECT operation_id FROM autoscaling_decisions WHERE resolved=0').get() as { operation_id: string };
const { scalingAdmission } = await import('../../src/lib/server/autoscaling/admission.js');
db().prepare("DELETE FROM server_keys WHERE server_id='t6_zombie_town_3'").run();
expect(scalingAdmission(id)).toContain('no longer eligible');
expect(scalingAdmission(id)).toBeNull();
scaling.setScalingGlobalPause(true);
expect(db().prepare('SELECT state FROM server_deployments WHERE id=?').get(id)).toEqual({ state: 'cancelled' });
expect(await scaling.runAutoscaling()).toBe(false);