Fix native provisioning scheduling and progress reporting

This commit is contained in:
2026-10-04 14:50:59 -04:00
parent 1bbee98b62
commit 2adadb0d05
18 changed files with 569 additions and 84 deletions
+21 -7
View File
@@ -14,6 +14,7 @@ import type { ProvisioningBlocker } from '../../provisioning-detail.js';
import { recordProgress } from './progress.js';
import { nativeInstance, nativeDeployment } from '../backends/native.js';
import { processNativeProvisioning } from './native.js';
import { trackActivity } from '../pipeline/activity.js';
const stoppedStates = new Set(['stopped', 'exited', 'created', 'dead']);
export const isStopped = (state?: string) => stoppedStates.has(state?.toLowerCase() ?? '');
@@ -91,16 +92,26 @@ function blocker(server: string, id: string, action: RuntimeAction): Provisionin
interface Operation { id: string; server: string; action: RuntimeAction; state: string; stage: string }
let ticking: Promise<void> | null = null;
export function processProvisioning(): Promise<void> {
if (ticking) return ticking;
ticking = run().finally(() => { ticking = null; });
return ticking;
let awaitedPass: Promise<void> | null = null;
export function processProvisioning(options: { wait?: boolean } = {}): Promise<void> {
if (options.wait !== false && awaitedPass) return awaitedPass;
// Native jobs own their individual flights. A slow observation must not
// prevent the next scheduler pass admitting newly arrived native work.
const native = nativePass(options);
if (!ticking) ticking = trackActivity('legacy-provisioning', 'Processing legacy provisioning', run)
.finally(() => { ticking = null; });
if (options.wait === false) {
void ticking.catch(error => console.error('[worker] legacy provisioning error:', error));
return native;
}
awaitedPass = Promise.all([native, ticking]).then(() => {}).finally(() => { awaitedPass = null; });
return awaitedPass;
}
export const processLifecycle = processProvisioning;
async function run(): Promise<void> {
await processNativeProvisioning(operation => {
function nativePass(options: { wait?: boolean }): Promise<void> {
return processNativeProvisioning(operation => {
if (operation.action === 'create') return null;
if (operation.action === 'destroy') {
const other = db().prepare(`SELECT id FROM server_deployments WHERE server=? AND id!=? AND server_deleted_at IS NULL
@@ -112,7 +123,10 @@ async function run(): Promise<void> {
if (eligibility === 'cancelled') { cancelProvisioning(operation.id, 'Requester cancelled or replaced this operation'); return 'Requester cancelled this operation.'; }
if (eligibility === 'held') return 'Waiting for the requester to resume.';
return blocker(operation.server, operation.id, typed.action)?.message ?? null;
});
}, options);
}
async function run(): Promise<void> {
await processCreations();
await processDestructions();
await refreshRestartRollout();