mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-04 07:19:52 +00:00
fix(render): scale timeout for long video encodes (#2244)
This commit is contained in:
@@ -154,6 +154,24 @@ describe("gif encode args", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe("runEncodeStage config plumbing", () => {
|
describe("runEncodeStage config plumbing", () => {
|
||||||
|
it("scales the encode timeout for long compositions", async () => {
|
||||||
|
const { runEncodeStage } = await import("./encodeStage.js");
|
||||||
|
|
||||||
|
await runEncodeStage(
|
||||||
|
makeInput({
|
||||||
|
job: {
|
||||||
|
...makeInput().job,
|
||||||
|
duration: 754.8,
|
||||||
|
},
|
||||||
|
engineConfig: { ffmpegEncodeTimeout: 600_000 },
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(encodeFramesFromDirMock.mock.calls[0]?.[5]).toEqual({
|
||||||
|
ffmpegEncodeTimeout: 3_019_200,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it("prefers engine config supplied by the orchestrator", async () => {
|
it("prefers engine config supplied by the orchestrator", async () => {
|
||||||
const { runEncodeStage } = await import("./encodeStage.js");
|
const { runEncodeStage } = await import("./encodeStage.js");
|
||||||
const orchestratorEngineConfig = { ffmpegEncodeTimeout: 54_321 };
|
const orchestratorEngineConfig = { ffmpegEncodeTimeout: 54_321 };
|
||||||
|
|||||||
@@ -277,6 +277,16 @@ export async function runEncodeStage(input: EncodeStageInput): Promise<EncodeSta
|
|||||||
// ── Stage 5: Encode ───────────────────────────────────────────────
|
// ── Stage 5: Encode ───────────────────────────────────────────────
|
||||||
updateJobStatus(job, "encoding", "Encoding video", 75, onProgress);
|
updateJobStatus(job, "encoding", "Encoding video", 75, onProgress);
|
||||||
|
|
||||||
|
// ffmpegEncodeTimeout is a total wall-clock cap, not an inactivity timeout.
|
||||||
|
// A fixed ten-minute cap reliably kills long high-quality disk-frame encodes
|
||||||
|
// that are still making progress. Preserve larger operator overrides while
|
||||||
|
// guaranteeing four seconds of encode budget per second of source video.
|
||||||
|
const scaledEncodeTimeout = Math.ceil((job.duration ?? 0) * 4_000);
|
||||||
|
const videoEngineCfg =
|
||||||
|
scaledEncodeTimeout > engineCfg.ffmpegEncodeTimeout
|
||||||
|
? { ...engineCfg, ffmpegEncodeTimeout: scaledEncodeTimeout }
|
||||||
|
: engineCfg;
|
||||||
|
|
||||||
const frameExt = needsAlpha ? "png" : "jpg";
|
const frameExt = needsAlpha ? "png" : "jpg";
|
||||||
const framePattern = `frame_%06d.${frameExt}`;
|
const framePattern = `frame_%06d.${frameExt}`;
|
||||||
const encoderOpts = {
|
const encoderOpts = {
|
||||||
@@ -305,7 +315,7 @@ export async function runEncodeStage(input: EncodeStageInput): Promise<EncodeSta
|
|||||||
encoderOpts,
|
encoderOpts,
|
||||||
chunkedEncodeSize,
|
chunkedEncodeSize,
|
||||||
abortSignal,
|
abortSignal,
|
||||||
engineCfg,
|
videoEngineCfg,
|
||||||
)
|
)
|
||||||
: await encodeFramesFromDir(
|
: await encodeFramesFromDir(
|
||||||
framesDir,
|
framesDir,
|
||||||
@@ -313,7 +323,7 @@ export async function runEncodeStage(input: EncodeStageInput): Promise<EncodeSta
|
|||||||
videoOnlyPath,
|
videoOnlyPath,
|
||||||
encoderOpts,
|
encoderOpts,
|
||||||
abortSignal,
|
abortSignal,
|
||||||
engineCfg,
|
videoEngineCfg,
|
||||||
);
|
);
|
||||||
assertNotAborted();
|
assertNotAborted();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user