fix(tags): time-box + self-resume the tag standardization (stop the 40-min timeout)
normalize_tags_task timed out at the 40-min hard limit on a large back-catalog
(the first run recases the whole booru vocabulary) — operator-flagged, and it
monopolized the concurrency-1 maintenance queue while doing so.
normalize_existing_tags now takes time_budget_seconds: the live run stops
cleanly at the budget and reports {partial, remaining}. The task runs 600s
chunks and re-enqueues itself until nothing remains (idempotent — commits per
group, so the next chunk skips already-canonical groups). Short chunks let the
recovery sweep and other maintenance tasks interleave instead of being blocked
for 40 minutes.
Frontend: the Standardize button is now fire-and-forget ("Queued — runs in the
background; re-run Preview to confirm") instead of poll-until-done, which would
have falsely reported "complete" after the first chunk.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -185,13 +185,9 @@
|
||||
:loading="normCommitting"
|
||||
@click="onNormCommit"
|
||||
>Standardize {{ normPreview.total_changes }} tag group(s)</v-btn>
|
||||
<span
|
||||
v-if="normResult"
|
||||
class="ml-3 text-caption"
|
||||
:class="normResult === 'ok' ? 'text-success' : 'text-warning'"
|
||||
>
|
||||
<template v-if="normResult === 'ok'">Standardization complete ✓</template>
|
||||
<template v-else>Finished with status: {{ normResult }}</template>
|
||||
<span v-if="normResult === 'queued'" class="ml-3 text-caption text-success">
|
||||
Queued ✓ — runs in the background (you can leave this page). It
|
||||
processes in chunks, so re-run “Preview” later to confirm it's all done.
|
||||
</span>
|
||||
</div>
|
||||
</v-card-text>
|
||||
@@ -289,13 +285,12 @@ async function onNormCommit() {
|
||||
normCommitting.value = true
|
||||
normResult.value = null
|
||||
try {
|
||||
// Long op (FK repoints): enqueue the maintenance task, then tail the
|
||||
// activity dashboard until its row reaches a terminal status. (The
|
||||
// per-run summary dict isn't exposed by /activity/runs, so we surface
|
||||
// the terminal status — the dry-run preview is the detailed view.)
|
||||
const { task_id: taskId } = await store.normalizeTags({ dryRun: false })
|
||||
const row = await store.pollTaskUntilDone(taskId)
|
||||
normResult.value = row?.status || 'ok'
|
||||
// Fire-and-forget: the task is time-boxed and self-resuming across chunks
|
||||
// (a large back-catalog can't finish in one run), so we DON'T poll-until-
|
||||
// done — that would falsely report "complete" after the first chunk. Just
|
||||
// confirm it's queued; the operator can re-run Preview later to verify.
|
||||
await store.normalizeTags({ dryRun: false })
|
||||
normResult.value = 'queued'
|
||||
normPreview.value = { total_changes: 0, tags_to_rename: 0, collisions: 0, tags_to_merge: 0, sample: [] }
|
||||
} finally {
|
||||
normCommitting.value = false
|
||||
|
||||
Reference in New Issue
Block a user