Skip to content

Commit 07ffecc

Browse files
committed
Treat server-side processing as non-fatal on upload
1 parent fb75731 commit 07ffecc

3 files changed

Lines changed: 20 additions & 26 deletions

File tree

apps/web/__tests__/unit/instant-recording-uploader.test.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -450,7 +450,7 @@ describe("InstantRecordingUploader", () => {
450450
);
451451
});
452452

453-
it("fails finalize when server-side processing cannot start", async () => {
453+
it("keeps finalize successful when server-side processing has not started yet", async () => {
454454
const fetchMock = vi.fn(
455455
async (input: RequestInfo | URL, init?: RequestInit) => {
456456
const url = input.toString();
@@ -499,7 +499,8 @@ describe("InstantRecordingUploader", () => {
499499
durationSeconds: 12,
500500
subpath: "raw-upload.webm",
501501
}),
502-
).rejects.toThrow("Video uploaded, but processing could not start");
502+
).resolves.toBeUndefined();
503+
expect(uploader.getProcessingStarted()).toBe(false);
503504
});
504505

505506
it("treats interrupted multipart completion as uncertain instead of fatal cleanup", async () => {

apps/web/app/(org)/dashboard/caps/components/web-recorder-dialog/instant-mp4-uploader.ts

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ const completeMultipartUpload = async (
134134
uploadId: string,
135135
parts: UploadedPartPayload[],
136136
meta: MultipartCompletePayload,
137-
) => {
137+
): Promise<{ processingStarted: boolean }> => {
138138
try {
139139
const response = await postJson<{
140140
success: boolean;
@@ -150,14 +150,10 @@ const completeMultipartUpload = async (
150150
fps: meta.fps,
151151
});
152152

153-
if (response.processingStarted === false) {
154-
throw new ProcessingStartError();
155-
}
153+
return {
154+
processingStarted: response.processingStarted !== false,
155+
};
156156
} catch (error) {
157-
if (error instanceof ProcessingStartError) {
158-
throw error;
159-
}
160-
161157
if (error instanceof HttpRequestError && error.status < 500) {
162158
throw error;
163159
}
@@ -214,6 +210,7 @@ export class InstantRecordingUploader {
214210
(error: CancelledUploadError) => void
215211
>();
216212
private readonly stallTimeouts = new Set<number>();
213+
private processingStarted = true;
217214

218215
constructor(options: {
219216
videoId: VideoId;
@@ -706,7 +703,7 @@ export class InstantRecordingUploader {
706703
throw new Error("No uploaded parts available for completion");
707704
}
708705

709-
await completeMultipartUpload(
706+
const completionResult = await completeMultipartUpload(
710707
this.videoId,
711708
this.uploadId,
712709
[...this.parts].sort((left, right) => left.partNumber - right.partNumber),
@@ -718,6 +715,7 @@ export class InstantRecordingUploader {
718715
subpath: options.subpath,
719716
},
720717
);
718+
this.processingStarted = completionResult.processingStarted;
721719

722720
this.finished = true;
723721
this.uploadedBytes = this.finalTotalBytes ?? this.uploadedBytes;
@@ -730,6 +728,10 @@ export class InstantRecordingUploader {
730728
await this.sendProgressUpdate(this.uploadedBytes, this.uploadedBytes);
731729
}
732730

731+
getProcessingStarted() {
732+
return this.processingStarted;
733+
}
734+
733735
async cancel() {
734736
if (this.finished) return;
735737
this.cancelled = true;

apps/web/app/(org)/dashboard/caps/components/web-recorder-dialog/useWebRecorder.ts

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ import {
1515
InstantRecordingUploader,
1616
initiateMultipartUpload,
1717
MultipartCompletionUncertainError,
18-
ProcessingStartError,
1918
} from "./instant-mp4-uploader";
2019
import type { RecordingMode } from "./RecordingModeSelector";
2120
import { captureThumbnail, convertToMp4 } from "./recording-conversion";
@@ -1223,6 +1222,12 @@ export const useWebRecorder = ({
12231222
fps,
12241223
subpath: rawSubpath,
12251224
});
1225+
1226+
if (!uploader.getProcessingStarted()) {
1227+
toast.warning(
1228+
"Recording uploaded. Processing did not start yet, but the original recording is available.",
1229+
);
1230+
}
12261231
} else {
12271232
const processedRecordingBlob =
12281233
pipeline.fileExtension === "mp4"
@@ -1359,20 +1364,6 @@ export const useWebRecorder = ({
13591364
console.error("Failed to process recording", err);
13601365
setUploadStatus(undefined);
13611366
const failureBlob = await resolveFailureBlob(rawRecordingBlob);
1362-
if (err instanceof ProcessingStartError) {
1363-
instantUploaderRef.current = null;
1364-
recordingPipelineRef.current = null;
1365-
pendingInstantVideoIdRef.current = null;
1366-
videoCreationRef.current = null;
1367-
replaceErrorDownload(failureBlob);
1368-
await disposeRecordingSpool();
1369-
updatePhase("error");
1370-
toast.error(
1371-
"Recording uploaded, but processing could not start. Open the video to retry processing.",
1372-
);
1373-
router.refresh();
1374-
return;
1375-
}
13761367
if (err instanceof MultipartCompletionUncertainError) {
13771368
instantUploaderRef.current = null;
13781369
recordingPipelineRef.current = null;

0 commit comments

Comments
 (0)