Cancel active provisioning jobs when rolling back betas
This commit is contained in:
@@ -1,14 +1,9 @@
|
||||
import { json } from '@sveltejs/kit';
|
||||
import { cancelRemoval } from '$lib/server/provisioning/history.js';
|
||||
import { cancelCreation } from '$lib/server/provisioning/cancel-creation.js';
|
||||
import { cancelProvisioningJob } from '$lib/server/provisioning/cancellation.js';
|
||||
import { kickProvisioning } from '$lib/server/pipeline/worker.js';
|
||||
|
||||
export function POST({ params }: { params: { id: string } }) {
|
||||
const cleanupId = cancelCreation(params.id);
|
||||
if (cleanupId) {
|
||||
void kickProvisioning();
|
||||
return json({ ok: true, cleanupId });
|
||||
}
|
||||
if (!cancelRemoval(params.id)) return json({ error: 'This operation can no longer be cancelled. Refresh to see its current state.' }, { status: 409 });
|
||||
if (!cancelProvisioningJob(params.id)) return json({ error: 'This operation can no longer be cancelled. Refresh to see its current state.' }, { status: 409 });
|
||||
void kickProvisioning();
|
||||
return json({ ok: true });
|
||||
}
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
import { json } from '@sveltejs/kit';
|
||||
import { cancelCreation } from '$lib/server/provisioning/cancel-creation.js';
|
||||
import { kickProvisioning } from '$lib/server/pipeline/worker.js';
|
||||
|
||||
export function POST({ params }: { params: { id: string } }) {
|
||||
const cleanupId = cancelCreation(params.id);
|
||||
if (!cleanupId) return json({ error: 'This creation can no longer be removed. Refresh its current state.' }, { status: 409 });
|
||||
void kickProvisioning();
|
||||
return json({ ok: true, cleanupId });
|
||||
}
|
||||
@@ -60,7 +60,7 @@
|
||||
try { const response = await fetch(`/api/provisioning/${encodeURIComponent(id)}/cancel`, { method: 'POST' }); if (response.ok) cancelled++; else unavailable.push(id); }
|
||||
catch { unavailable.push(id); }
|
||||
}
|
||||
cancellationNotice = `${cancelled} queued removal${cancelled === 1 ? '' : 's'} cancelled.${cancelled ? ' The servers covered by those cancelled requests and their files were kept.' : ''}${unavailable.length ? ` ${unavailable.length} could not be cancelled; refresh their operations to see whether removal has begun.` : ''}`;
|
||||
cancellationNotice = `${cancelled} operation${cancelled === 1 ? '' : 's'} cancelled.${unavailable.length ? ` ${unavailable.length} could not be cancelled; refresh to see their current state.` : ''}`;
|
||||
cancelling = false; await load();
|
||||
}
|
||||
const tabs = $derived.by(() => [{id:'active',label:'Active',badge:active.length},{id:'history',label:'History'}]);
|
||||
@@ -122,7 +122,7 @@
|
||||
{#if error}<p role="alert" class="error">{error} <button onclick={() => void load()}>Retry</button></p>{/if}
|
||||
{#if tab === 'active'}
|
||||
{#if needsReview}<div class="ui-summary"><span>{needsReview} recorded operations need review</span><Button size="sm" onclick={() => { historyState = 'attention'; tab = 'history'; saveContext(true); }}>Review history</Button></div>{/if}
|
||||
{#if active.some(d => d.canCancelRemoval)}<div class="ui-summary"><span>Waiting removals can be withdrawn until removal begins. Running and completed removals cannot be reversed.</span><Button disabled={cancelling} onclick={() => cancelRequests(active.filter(d => d.canCancelRemoval).map(d => d.id))}>Cancel all waiting removals</Button></div>{/if}
|
||||
{#if active.some(d => d.canCancel)}<div class="ui-summary"><span>Cancelling stops remaining work and health checks. Changes already made are not undone.</span><Button disabled={cancelling} onclick={() => cancelRequests(active.filter(d => d.canCancel).map(d => d.id))}>Cancel all active operations</Button></div>{/if}
|
||||
<section>
|
||||
<h2>In flight <span>{active.length}</span></h2>
|
||||
{#if loading}<p>Loading provisioning activity...</p>
|
||||
@@ -165,7 +165,7 @@
|
||||
<div class="meta"><span>Started {fmt(d.started_at)}</span>{#if d.finished_at}<span>Finished {fmt(d.finished_at)}</span>{/if}<span>By {d.triggered_by}</span></div>
|
||||
{#if d.error}<p class="error">{d.error}</p>{/if}
|
||||
{#each warnings(d) as warning}<p class="error">{warning}</p>{/each}
|
||||
</a>{#if d.canCancelRemoval && !d.server_deleted_at}<div class="row-actions"><Button size="sm" disabled={cancelling} onclick={() => cancelRequests([d.id])}>Cancel queued removal</Button></div>{/if}</article>
|
||||
</a>{#if d.canCancel && !d.server_deleted_at}<div class="row-actions"><Button size="sm" disabled={cancelling} onclick={() => cancelRequests([d.id])}>Cancel operation</Button></div>{/if}</article>
|
||||
{/snippet}
|
||||
|
||||
<style>
|
||||
|
||||
@@ -89,13 +89,13 @@
|
||||
{#if detail.activity.failureExcerpt && detail.activity.failureExcerpt.message !== deployment.error && ['failed', 'interrupted'].includes(deployment.state)}<p class="failure-excerpt"><span>Last failure event · {fmt(detail.activity.failureExcerpt.created_at)}</span>{detail.activity.failureExcerpt.message}</p>{/if}
|
||||
{#if detail.warningMessages.length}<div class="warnings"><h3>Recorded warnings</h3><ul>{#each detail.warningMessages as warning}<li>{warning}</li>{/each}</ul></div>{/if}
|
||||
|
||||
{#if detail.canResumeVerification || detail.canResumeCleanup || detail.canResumeRebuild || detail.canCancelRemoval || detail.canCancelCreation}
|
||||
{#if detail.canResumeVerification || detail.canResumeCleanup || detail.canResumeRebuild || detail.canCancel || detail.canCancelCreation}
|
||||
<div class="recovery-actions">
|
||||
{#if detail.canResumeVerification}<Button variant="primary" loading={view.busy === 'resume'} disabled={!!view.busy} onclick={() => controller.act('resume', 'Health verification requested. The existing instance will be observed without another creation or restart.')}>Resume health verification</Button>{/if}
|
||||
{#if detail.canResumeRebuild}<Button variant="primary" loading={view.busy === 'resume'} disabled={!!view.busy} onclick={() => controller.act('resume', 'Rebuild cleanup requested. Fresh creation waits for local cleanup to finish.')}>Resume rebuild cleanup</Button>{/if}
|
||||
{#if detail.canResumeCleanup}<Button variant="primary" loading={view.busy === 'resume'} disabled={!!view.busy} onclick={() => controller.act('resume', 'Local cleanup requested. Remote container deletion will not be repeated.')}>Resume cleanup</Button>{/if}
|
||||
{#if detail.canCancelRemoval}<div><Button disabled={!!view.busy} loading={view.busy === 'cancel'} onclick={() => controller.act('cancel', 'Queued removal cancelled. The server and its files were kept.')}>Cancel queued removal</Button><p class="action-help">Available until removal begins. Cancelling keeps the server and its files.</p></div>{/if}
|
||||
{#if detail.canCancelCreation}<div><Button variant="danger" disabled={!!view.busy} loading={view.busy === 'cancel'} onclick={() => controller.act('cancel', 'Creation cancelled. Follow cleanup below until removal is confirmed.')}>Cancel creation and remove server</Button><p class="action-help">Stops this launch and deletes its container and instance files, even if player status is unknown or players have joined. Shared game files and the saved server key are kept.</p></div>{/if}
|
||||
{#if detail.canCancel}<div><Button disabled={!!view.busy} loading={view.busy === 'cancel'} onclick={() => controller.act('cancel', 'Operation cancelled. Already-submitted commands may finish; no further steps will be started.')}>Cancel operation</Button><p class="action-help">Stops remaining work and health checks. Changes already made are not undone.</p></div>{/if}
|
||||
{#if detail.canCancelCreation}<div><Button variant="danger" disabled={!!view.busy} loading={view.busy === 'cancel-creation'} onclick={() => controller.act('cancel-creation', 'Creation cancelled. Follow cleanup below until removal is confirmed.')}>Cancel creation and remove server</Button><p class="action-help">Stops this launch and deletes its container and instance files, even if player status is unknown or players have joined. Shared game files and the saved server key are kept.</p></div>{/if}
|
||||
</div>
|
||||
{/if}
|
||||
{#if detail.cancellation}<div class="recovery-note"><strong>{detail.cancellation.state === 'done' ? 'Cancellation cleanup completed' : 'Cancellation cleanup'}</strong><p>{detail.cancellation.error ?? detail.cancellation.stage}</p><a href={`/provisioning/${encodeURIComponent(detail.cancellation.cleanupId)}`}>View cleanup progress →</a></div>{/if}
|
||||
|
||||
Reference in New Issue
Block a user