fix: capture job baseline before POST to avoid race condition
The previous version snapshotted last_run_id after the 201 response, but jobs fire immediately server-side — by the time the client fetched /api/jobs the runs were already complete, so the baseline matched the new state and the poll loop never detected completion. Baseline is now captured before the creation POST so it always reflects pre-run state regardless of job speed. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
16
js/ui.js
16
js/ui.js
@@ -289,6 +289,10 @@ async function saveInstance() {
|
|||||||
hardware_acceleration: +document.getElementById('f-hardware-accel').checked,
|
hardware_acceleration: +document.getElementById('f-hardware-accel').checked,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Snapshot job state before creation — jobs fire immediately after the 201
|
||||||
|
// so the baseline must be captured before the POST, not after.
|
||||||
|
const jobBaseline = !editingVmid ? await _snapshotJobBaseline() : null;
|
||||||
|
|
||||||
const result = editingVmid
|
const result = editingVmid
|
||||||
? await updateInstance(editingVmid, data)
|
? await updateInstance(editingVmid, data)
|
||||||
: await createInstance(data);
|
: await createInstance(data);
|
||||||
@@ -298,7 +302,7 @@ async function saveInstance() {
|
|||||||
showToast(`${name} ${editingVmid ? 'updated' : 'created'}`, 'success');
|
showToast(`${name} ${editingVmid ? 'updated' : 'created'}`, 'success');
|
||||||
closeModal();
|
closeModal();
|
||||||
|
|
||||||
if (!editingVmid) await _waitForOnCreateJobs();
|
if (jobBaseline) await _waitForOnCreateJobs(jobBaseline);
|
||||||
|
|
||||||
if (currentVmid && document.getElementById('page-detail').classList.contains('active')) {
|
if (currentVmid && document.getElementById('page-detail').classList.contains('active')) {
|
||||||
await renderDetailPage(vmid);
|
await renderDetailPage(vmid);
|
||||||
@@ -307,16 +311,18 @@ async function saveInstance() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function _waitForOnCreateJobs() {
|
async function _snapshotJobBaseline() {
|
||||||
|
const jobs = await fetch('/api/jobs').then(r => r.json());
|
||||||
|
return new Map(jobs.map(j => [j.id, j.last_run_id ?? null]));
|
||||||
|
}
|
||||||
|
|
||||||
|
async function _waitForOnCreateJobs(baseline) {
|
||||||
const jobs = await fetch('/api/jobs').then(r => r.json());
|
const jobs = await fetch('/api/jobs').then(r => r.json());
|
||||||
const relevant = jobs.filter(j => {
|
const relevant = jobs.filter(j => {
|
||||||
try { return JSON.parse(j.config || '{}').run_on_create; } catch { return false; }
|
try { return JSON.parse(j.config || '{}').run_on_create; } catch { return false; }
|
||||||
});
|
});
|
||||||
if (!relevant.length) return;
|
if (!relevant.length) return;
|
||||||
|
|
||||||
// Snapshot run IDs before jobs fire so we can detect new completions
|
|
||||||
const baseline = new Map(relevant.map(j => [j.id, j.last_run_id ?? null]));
|
|
||||||
|
|
||||||
const deadline = Date.now() + 30_000;
|
const deadline = Date.now() + 30_000;
|
||||||
while (Date.now() < deadline) {
|
while (Date.now() < deadline) {
|
||||||
await new Promise(r => setTimeout(r, 500));
|
await new Promise(r => setTimeout(r, 500));
|
||||||
|
|||||||
Reference in New Issue
Block a user