Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions packages/cli/src/commands/render.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,11 @@ const preflightState = vi.hoisted(() => ({
},
}));

const orphanCleanupState = vi.hoisted(() => ({
calls: 0,
killed: 0,
}));

vi.mock("../utils/producer.js", () => ({
loadProducer: vi.fn(async () => ({
resolveConfig: vi.fn((overrides: Record<string, unknown>) => {
Expand Down Expand Up @@ -128,6 +133,13 @@ vi.mock("../browser/preflight.js", () => ({
runEnvironmentChecks: vi.fn(async () => preflightState.result),
}));

vi.mock("../utils/orphanCleanup.js", () => ({
killOrphanedProcesses: vi.fn(() => {
orphanCleanupState.calls += 1;
return orphanCleanupState.killed;
}),
}));

describe("renderLocal browser GPU config", () => {
const savedEnv = new Map<string, string | undefined>();
// Pre-resolve once. The first dynamic `import("./render.js")` in this file
Expand Down Expand Up @@ -173,6 +185,8 @@ describe("renderLocal browser GPU config", () => {
configState.writeConfigCalls = [];
trackingState.shouldTrack = true;
trackingState.renderObservations = [];
orphanCleanupState.calls = 0;
orphanCleanupState.killed = 0;
resetTrialState();
savedEnv.clear();
savedEnv.set("HYPERFRAMES_FFMPEG_PATH", process.env.HYPERFRAMES_FFMPEG_PATH);
Expand All @@ -185,6 +199,22 @@ describe("renderLocal browser GPU config", () => {
delete process.env.HF_DE_PARALLEL_ROUTER;
});

it("cleans orphaned browser trees before starting a local render", async () => {
orphanCleanupState.killed = 1;

await renderLocal("/tmp/project", "/tmp/out.mp4", {
fps: { num: 30, den: 1 },
quality: "standard",
format: "mp4",
gpu: false,
browserGpuMode: "software",
hdrMode: "auto",
quiet: true,
});

expect(orphanCleanupState.calls).toBe(1);
});

afterEach(() => {
for (const [key, value] of savedEnv) {
if (value === undefined) {
Expand Down
10 changes: 10 additions & 0 deletions packages/cli/src/commands/render.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ import { buildDockerRunArgs, resolveDockerPlatform } from "../utils/dockerRunArg
import { normalizeErrorMessage } from "../utils/errorMessage.js";
import { runEnvironmentChecks } from "../browser/preflight.js";
import { chromeLaunchRemediation } from "../browser/linuxDeps.js";
import { killOrphanedProcesses } from "../utils/orphanCleanup.js";
import type { ProducerLogger, RenderJob } from "@hyperframes/producer";
import {
MAX_VP9_CPU_USED,
Expand Down Expand Up @@ -1425,6 +1426,15 @@ export async function renderLocal(
outputPath: string,
options: RenderOptions,
): Promise<SingleRenderResult> {
const recoveredOrphanTrees = killOrphanedProcesses();
if (recoveredOrphanTrees > 0 && !options.quiet) {
console.warn(
c.warn(
` Recovered ${recoveredOrphanTrees} orphaned browser process ${recoveredOrphanTrees === 1 ? "tree" : "trees"} from an interrupted render.`,
),
);
}

const preflight = await runEnvironmentChecks({
projectDir,
browserPath: options.browserPath,
Expand Down
Loading