feat: add retry/delete for jobs
Build & Push Docker Image / build-and-push (push) Successful in 41s

- db.ts: add resetJob() and deleteJob() statements + exports
- pipeline.ts: export retryJob() — resets job state and re-runs pipeline
- DELETE /api/jobs/[id]: hard-delete terminal jobs (done/failed/cancelled);
  keep cancel-only behavior for active jobs
- POST /api/jobs/[id]/retry: new endpoint; validates failed/cancelled URL job,
  resets and re-runs via retryJob()
- jobs/[id]/+page.svelte: wire Cancel/Retry/Delete buttons with fetch calls;
  fix hardcoded ACCENT → accent store
- jobs/+page.svelte: per-row Retry+Delete icon buttons (visible on hover);
  fix hardcoded ACCENT → accent store

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
Giancarmine Salucci
2026-05-06 17:42:54 +02:00
co-authored by Copilot
parent 37175ec791
commit d1295ce343
6 changed files with 207 additions and 15 deletions
+17
View File
@@ -59,6 +59,15 @@ const stmts = {
UPDATE jobs SET status = @status, progress = @progress, updated_at = datetime('now')
WHERE id = @id
`),
resetJob: db.prepare(`
UPDATE jobs SET
status = 'pending', progress = 0, error = NULL,
mean_volume = NULL, whisper_job_id = NULL,
output_dir = NULL, segments_json = NULL,
updated_at = datetime('now')
WHERE id = @id
`),
deleteJob: db.prepare('DELETE FROM jobs WHERE id = ?'),
getJob: db.prepare('SELECT * FROM jobs WHERE id = ?'),
listJobs: db.prepare('SELECT * FROM jobs ORDER BY created_at DESC, rowid DESC LIMIT 100'),
upsertSub: db.prepare(`
@@ -135,3 +144,11 @@ export function getAllSubscriptions(): PushSubscription[] {
export function deletePushSubscription(endpoint: string): void {
stmts.deleteSub.run(endpoint);
}
export function resetJob(id: string): void {
stmts.resetJob.run({ id });
}
export function deleteJob(id: string): void {
stmts.deleteJob.run(id);
}
+11 -1
View File
@@ -1,4 +1,4 @@
import { createJob, updateJob, setJobStatus, getJob } from './db.js';
import { createJob, updateJob, setJobStatus, getJob, resetJob } from './db.js';
import { downloadYouTube, saveUploadedFile, cleanupJobTmp } from './downloader.js';
import { prepareAudio, cleanup as cleanupFiles } from './audio.js';
import { submitJob, streamJob } from './whisper.js';
@@ -50,6 +50,16 @@ export async function startUploadJob(
return job.id;
}
/** Retry a failed/cancelled YouTube job by resetting and re-running the pipeline. */
export async function retryJob(jobId: string): Promise<void> {
const job = getJob(jobId);
if (!job) throw new Error('Job not found');
resetJob(jobId);
runJob(jobId, { type: 'youtube', url: job.source }, job.audioMode as AudioMode).catch((err) => {
console.error(`[pipeline] retry job ${jobId} failed:`, err);
});
}
async function runJob(
jobId: string,
input: { type: 'youtube'; url: string } | { type: 'upload'; buffer: Buffer; filename: string },