Skip to content

Commit 53503b5

Browse files
committed
fix: keep media retries non-terminal
1 parent 5cee3fa commit 53503b5

4 files changed

Lines changed: 87 additions & 30 deletions

File tree

apps/web/app/api/webhooks/media-server/progress/route.ts

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,9 @@ export async function POST(request: NextRequest) {
7676
}
7777

7878
const payload: ProgressWebhookPayload = await request.json();
79+
const isRetryableWorkflowError =
80+
request.nextUrl.searchParams.get("retryable") === "true" &&
81+
payload.phase === "error";
7982

8083
console.log(
8184
"[media-server-webhook] Received progress update for video %s: %s (%d%%)",
@@ -192,22 +195,38 @@ export async function POST(request: NextRequest) {
192195
currentVideo?.storageIntegrationId,
193196
);
194197
} else if (dbPhase === "error") {
195-
await db()
196-
.update(videoUploads)
197-
.set({
198-
phase: "error",
199-
processingError: payload.error || payload.message || "Unknown error",
200-
processingMessage: payload.message,
201-
updatedAt: new Date(),
202-
})
203-
.where(eq(videoUploads.videoId, payload.videoId as Video.VideoId));
198+
const processingError =
199+
payload.error || payload.message || "Unknown error";
200+
if (isRetryableWorkflowError) {
201+
await db()
202+
.update(videoUploads)
203+
.set({
204+
phase: "processing",
205+
processingProgress: Math.round(payload.progress),
206+
processingError,
207+
processingMessage: "Retrying video processing...",
208+
updatedAt: new Date(),
209+
})
210+
.where(eq(videoUploads.videoId, payload.videoId as Video.VideoId));
211+
} else {
212+
await db()
213+
.update(videoUploads)
214+
.set({
215+
phase: "error",
216+
processingError,
217+
processingMessage: payload.message,
218+
updatedAt: new Date(),
219+
})
220+
.where(eq(videoUploads.videoId, payload.videoId as Video.VideoId));
221+
}
204222
} else {
205223
await db()
206224
.update(videoUploads)
207225
.set({
208226
phase: dbPhase,
209227
processingProgress: Math.round(payload.progress),
210228
processingMessage: payload.message,
229+
processingError: null,
211230
updatedAt: new Date(),
212231
})
213232
.where(eq(videoUploads.videoId, payload.videoId as Video.VideoId));

apps/web/workflows/edit-video.ts

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -282,9 +282,20 @@ async function renderVideoEditOnMediaServer(
282282
)
283283
.pipe(runPromise);
284284

285-
const webhookUrl = `${webhookBaseUrl}/api/webhooks/media-server/progress`;
285+
const webhookUrl = `${webhookBaseUrl}/api/webhooks/media-server/progress?retryable=true`;
286286
const webhookSecret = serverEnv().MEDIA_SERVER_WEBHOOK_SECRET;
287287

288+
await db()
289+
.update(videoUploads)
290+
.set({
291+
phase: "processing",
292+
processingProgress: 0,
293+
processingMessage: "Starting video edit...",
294+
processingError: null,
295+
updatedAt: new Date(),
296+
})
297+
.where(eq(videoUploads.videoId, videoId as Video.VideoId));
298+
288299
await startMediaServerEditJob(mediaServerUrl, {
289300
videoId,
290301
userId,
@@ -426,12 +437,12 @@ async function waitForEditCompletion(
426437
return { metadata };
427438
}
428439

440+
if (upload.processingError) {
441+
throw new Error(upload.processingError);
442+
}
443+
429444
if (upload.phase === "error") {
430-
throw new Error(
431-
upload.processingError ||
432-
upload.processingMessage ||
433-
"Video edit failed",
434-
);
445+
throw new Error(upload.processingMessage || "Video edit failed");
435446
}
436447

437448
lastStatus = [

apps/web/workflows/import-loom-video.ts

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -369,7 +369,7 @@ async function processVideoOnMediaServer(
369369
): Promise<MediaServerProcessResult> {
370370
"use step";
371371

372-
const { videoId, userId, rawFileKey } = payload;
372+
const { videoId, userId, rawFileKey, loomVideoId } = payload;
373373

374374
const mediaServerUrl = serverEnv().MEDIA_SERVER_URL;
375375
if (!mediaServerUrl) {
@@ -443,9 +443,25 @@ async function processVideoOnMediaServer(
443443
};
444444
}).pipe(runPromise);
445445

446-
const webhookUrl = `${webhookBaseUrl}/api/webhooks/media-server/progress`;
446+
const webhookUrl = `${webhookBaseUrl}/api/webhooks/media-server/progress?retryable=true`;
447447
const webhookSecret = serverEnv().MEDIA_SERVER_WEBHOOK_SECRET;
448-
const sourceVideoUrl = processingInput.sourceVideoUrl ?? rawVideoUrl;
448+
const sourceVideoUrl = processingInput.sourceVideoUrl
449+
? await fetchFreshLoomDownloadUrl(loomVideoId)
450+
: rawVideoUrl;
451+
const inputExtension = processingInput.sourceVideoUrl
452+
? getInputExtension(sourceVideoUrl)
453+
: processingInput.inputExtension;
454+
455+
await db()
456+
.update(videoUploads)
457+
.set({
458+
phase: "processing",
459+
processingProgress: 0,
460+
processingMessage: "Starting video processing...",
461+
processingError: null,
462+
updatedAt: new Date(),
463+
})
464+
.where(eq(videoUploads.videoId, videoId as Video.VideoId));
449465

450466
await startMediaServerProcessJob(mediaServerUrl, {
451467
videoId,
@@ -456,7 +472,7 @@ async function processVideoOnMediaServer(
456472
previewGifPresignedUrl,
457473
webhookUrl,
458474
webhookSecret: webhookSecret || undefined,
459-
inputExtension: processingInput.inputExtension,
475+
inputExtension,
460476
});
461477

462478
return await waitForProcessingCompletion(videoId);
@@ -536,12 +552,12 @@ async function waitForProcessingCompletion(
536552
return { metadata };
537553
}
538554

555+
if (upload.processingError) {
556+
throw new Error(upload.processingError);
557+
}
558+
539559
if (upload.phase === "error") {
540-
throw new Error(
541-
upload.processingError ||
542-
upload.processingMessage ||
543-
"Loom import failed",
544-
);
560+
throw new Error(upload.processingMessage || "Loom import failed");
545561
}
546562

547563
lastStatus = [

apps/web/workflows/process-video.ts

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -287,9 +287,20 @@ async function processVideoOnMediaServer(
287287
)
288288
.pipe(runPromise);
289289

290-
const webhookUrl = `${webhookBaseUrl}/api/webhooks/media-server/progress`;
290+
const webhookUrl = `${webhookBaseUrl}/api/webhooks/media-server/progress?retryable=true`;
291291
const webhookSecret = serverEnv().MEDIA_SERVER_WEBHOOK_SECRET;
292292

293+
await db()
294+
.update(videoUploads)
295+
.set({
296+
phase: "processing",
297+
processingProgress: 0,
298+
processingMessage: "Starting video processing...",
299+
processingError: null,
300+
updatedAt: new Date(),
301+
})
302+
.where(eq(videoUploads.videoId, videoId as Video.VideoId));
303+
293304
await startMediaServerProcessJob(mediaServerUrl, {
294305
videoId,
295306
userId,
@@ -379,12 +390,12 @@ async function waitForProcessingCompletion(
379390
return { metadata };
380391
}
381392

393+
if (upload.processingError) {
394+
throw new Error(upload.processingError);
395+
}
396+
382397
if (upload.phase === "error") {
383-
throw new Error(
384-
upload.processingError ||
385-
upload.processingMessage ||
386-
"Video processing failed",
387-
);
398+
throw new Error(upload.processingMessage || "Video processing failed");
388399
}
389400

390401
lastStatus = [

0 commit comments

Comments
 (0)