Skip to content

Commit

Permalink
Merge pull request #11195 from quarto-dev/fix/chrome-cleaning
Browse files Browse the repository at this point in the history
  • Loading branch information
cderv authored Oct 25, 2024
2 parents c96fe72 + c8a3e7c commit d905295
Show file tree
Hide file tree
Showing 3 changed files with 28 additions and 5 deletions.
1 change: 1 addition & 0 deletions news/changelog-1.6.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ All changes included in 1.6:

- ([#11135](https://github.com/quarto-dev/quarto-cli/issues/11135)): Use `--headless=old` mode for Chromium to avoid recent issues with the new `--headless` mode. Setting `--headless=new` can be configured with `QUARTO_CHROMIUM_HEADLESS_MODE=new` environment variable, however it is not recommended new headless mode seems to be unstable. Only use to be unblocked of a situation (like `QUARTO_CHROMIUM_HEADLESS_MODE="none"` if you use an old chrome version somehow that don't support `--headless=old`).
- ([#10170](https://github.com/quarto-dev/quarto-cli/issues/10170)): Quarto should find chrome executable automatically on most OS. If this is does not find it, or a specific version is needed, set `QUARTO_CHROMIUM` environment variable to the executable path.
- Quarto now makes sure that all started chromium instances are closed when the process ends, no matter how it ends (success, error, or interruption).

## Other Fixes and Improvements

Expand Down
15 changes: 14 additions & 1 deletion src/core/cri/cri.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ import { InternalError } from "../lib/error.ts";
import { getenv } from "../env.ts";
import { kRenderFileLifetime } from "../../config/constants.ts";
import { debug } from "../../deno_ral/log.ts";
import {
registerForExitCleanup,
unregisterForExitCleanup,
} from "../process.ts";

async function waitForServer(port: number, timeout = 3000) {
const interval = 50;
Expand Down Expand Up @@ -101,6 +105,9 @@ export async function criClient(appPath?: string, port?: number) {
];
const browser = Deno.run({ cmd, stdout: "piped", stderr: "piped" });

// Register for cleanup inside exitWithCleanup() in case something goes wrong
const thisProcessId = registerForExitCleanup(browser);

if (!(await waitForServer(port as number))) {
let msg = "Couldn't find open server.";
// Printing more error information if chrome process errored
Expand All @@ -121,7 +128,13 @@ export async function criClient(appPath?: string, port?: number) {
const result = {
close: async () => {
await client.close();
browser.close();
// FIXME: 2024-10
// We have a bug where `client.close()` doesn't return properly and we don't go below
// meaning the `browser` process is not killed here, and it will be handled in exitWithCleanup().

browser.kill(); // Chromium headless won't terminate on its own, so we need to send kill signal
browser.close(); // Closing the browser Deno process
unregisterForExitCleanup(thisProcessId); // All went well so not need to cleanup on quarto exit
},

rawClient: () => client,
Expand Down
17 changes: 13 additions & 4 deletions src/core/process.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,16 @@ const processList = new Map<number, Deno.Process>();
let processCount = 0;
let cleanupRegistered = false;

export function registerForExitCleanup(process: Deno.Process) {
const thisProcessId = ++processCount; // don't risk repeated PIDs
processList.set(thisProcessId, process);
return thisProcessId;
}

export function unregisterForExitCleanup(processId: number) {
processList.delete(processId);
}

function ensureCleanup() {
if (!cleanupRegistered) {
cleanupRegistered = true;
Expand Down Expand Up @@ -61,12 +71,11 @@ export async function execProcess(
stdout: typeof (options.stdout) === "number" ? options.stdout : "piped",
stderr: typeof (options.stderr) === "number" ? options.stderr : "piped",
});
const thisProcessId = ++processCount; // don't risk repeated PIDs
processList.set(thisProcessId, process);
const thisProcessId = registerForExitCleanup(process);

if (stdin !== undefined) {
if (!process.stdin) {
processList.delete(processCount);
unregisterForExitCleanup(thisProcessId);
throw new Error("Process stdin not available");
}
// write in 4k chunks (deno observed to overflow at > 64k)
Expand Down Expand Up @@ -170,7 +179,7 @@ export async function execProcess(
// close the process
process.close();

processList.delete(thisProcessId);
unregisterForExitCleanup(thisProcessId);

debug(`[execProcess] Success: ${status.success}, code: ${status.code}`);

Expand Down

0 comments on commit d905295

Please sign in to comment.