Skip to content

Commit c91971f

Browse files
committed
fix race condition on multiple simultaneous renders with preview
1 parent 2dbf319 commit c91971f

File tree

2 files changed

+29
-3
lines changed

2 files changed

+29
-3
lines changed

src/command/render/render-files.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,10 @@ import {
7878
} from "./freeze.ts";
7979
import { isJupyterNotebook } from "../../core/jupyter/jupyter.ts";
8080
import { MappedString } from "../../core/lib/text-types.ts";
81-
import { createNamedLifetime } from "../../core/lifetimes.ts";
81+
import {
82+
createNamedLifetime,
83+
waitUntilNamedLifetime,
84+
} from "../../core/lifetimes.ts";
8285
import { resolveDependencies } from "./pandoc-dependencies-html.ts";
8386
import {
8487
getData as getTimingData,
@@ -390,7 +393,7 @@ export async function renderFiles(
390393
);
391394
}
392395

393-
const fileLifetime = createNamedLifetime("render-file");
396+
const fileLifetime = await waitUntilNamedLifetime("render-file");
394397
fileLifetime.attach({
395398
cleanup() {
396399
resetFigureCounter();

src/core/lifetimes.ts

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,41 @@ export interface ObjectWithLifetime {
99
cleanup(): Promise<void> | void;
1010
}
1111

12+
type PromiseResolver = (value: Lifetime | PromiseLike<Lifetime>) => void;
1213
const _globalLifetimes: Record<string, Lifetime> = {};
14+
const _globalAwaitQueues: Record<string, PromiseResolver[]> = {};
15+
16+
export function waitUntilNamedLifetime(name: string): Promise<Lifetime> {
17+
const lt = getNamedLifetime(name);
18+
if (lt === undefined) {
19+
return Promise.resolve(createNamedLifetime(name));
20+
}
21+
22+
// let reject: any; FIXME figure out what to do with rejects
23+
const promise = new Promise<Lifetime>((resolve) => {
24+
if (_globalAwaitQueues[name] === undefined) {
25+
_globalAwaitQueues[name] = [];
26+
}
27+
_globalAwaitQueues[name].push(resolve);
28+
});
29+
return promise;
30+
}
1331

1432
export function createNamedLifetime(name: string): Lifetime {
1533
if (_globalLifetimes[name] !== undefined) {
1634
throw new Error(
17-
`Internal Error: cannot recreate existing named lifetime ${name}`,
35+
`Internal Error: lifetime ${name} already exists. This is a bug in Quarto.`,
1836
);
1937
}
2038
const lifetime = new Lifetime();
2139
lifetime.attach({
2240
cleanup: () => {
2341
delete _globalLifetimes[name];
42+
if (_globalAwaitQueues[name] && _globalAwaitQueues[name].length) {
43+
const resolver = _globalAwaitQueues[name].shift()!;
44+
const newLifetime = createNamedLifetime(name);
45+
resolver(newLifetime);
46+
}
2447
},
2548
});
2649
_globalLifetimes[name] = lifetime;

0 commit comments

Comments
 (0)