Keep native collection launches responsive

This commit is contained in:
2026-10-05 10:48:38 -04:00
parent dbd2940d29
commit 1405114a14
26 changed files with 998 additions and 123 deletions
+32 -2
View File
@@ -246,7 +246,9 @@ describe('native instance provisioning', () => {
try {
const { getDeployment } = await import('../../src/lib/server/provisioning/history.js');
expect(getDeployment(first.deploymentId)!.progress?.phase).toBe('verify-container');
expect((await operationFor(second.deploymentId))?.kind).toBe('instance.create');
await vi.waitFor(async () => {
expect((await operationFor(second.deploymentId))?.kind).toBe('instance.create');
}, { timeout: 5_000 });
} finally {
release({ healthy: true, state: 'running' } as never);
await pending;
@@ -268,7 +270,9 @@ describe('native instance provisioning', () => {
try {
const second = await queue();
await processProvisioning({ wait: false });
expect((await operationFor(second.deploymentId))?.kind).toBe('instance.create');
await vi.waitFor(async () => {
expect((await operationFor(second.deploymentId))?.kind).toBe('instance.create');
}, { timeout: 5_000 });
expect(vi.mocked(nativeRequest)).toHaveBeenCalledTimes(1);
} finally {
release({ healthy: true, state: 'running' } as never);
@@ -401,6 +405,32 @@ describe('native instance provisioning', () => {
await advance();
expect(nativeInstance(job.name)?.generation).toBe(2);
});
it('holds a rebuild when players join while its launch files are being prepared', async () => {
const job = await queue(); await advance(); await acknowledge(job.deploymentId);
const { queueNativeRebuild } = await import('../../src/lib/server/provisioning/native.js');
const rebuild = queueNativeRebuild(job.name, 'test'); if (!rebuild.ok) throw new Error(rebuild.message);
const preparation = await import('../../src/lib/server/provisioning/launch-preparation.js');
const prepare = preparation.prepareNativeLaunch;
let started!: () => void;
let release!: () => void;
const ready = new Promise<void>(resolve => { started = resolve; });
const gate = new Promise<void>(resolve => { release = resolve; });
const spy = vi.spyOn(preparation, 'prepareNativeLaunch').mockImplementationOnce(async input => {
const result = await prepare(input);
started(); await gate;
return result;
});
const pending = advance();
try {
await ready;
remote.players = 2;
release(); await pending;
expect(await operationFor(rebuild.deploymentId)).toBeNull();
remote.players = 0;
await advance();
expect((await operationFor(rebuild.deploymentId))?.kind).toBe('instance.rebuild');
} finally { release(); await pending; spy.mockRestore(); }
});
it('finishes native rebuild verification without waiting for its own recovery slot to be released', async () => {
const job = await queue(); await advance(); await acknowledge(job.deploymentId);
const { queueNativeRebuild } = await import('../../src/lib/server/provisioning/native.js');