Skip to content

Commit 424d7b4

Browse files
committed
saw a project log in production where this kernelspec was called 466 times at once
- surely due to the accumulation from bad clients, etc. - but since "jupyter kernelspec list" on a cocalc project could take 2-3 seconds, this could break a lot - so reuseInFlight!
1 parent ae7c510 commit 424d7b4

File tree

1 file changed

+34
-30
lines changed

1 file changed

+34
-30
lines changed

src/packages/jupyter/kernel/kernel-data.ts

Lines changed: 34 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,9 @@ Specs: https://jupyter-client.readthedocs.io/en/stable/kernels.html#kernel-specs
1313

1414
import { findAll } from "kernelspecs";
1515
import LRU from "lru-cache";
16-
1716
import type { KernelSpec } from "@cocalc/jupyter/types/types";
1817
import { field_cmp } from "@cocalc/util/misc";
18+
import { reuseInFlight } from "@cocalc/util/reuse-in-flight";
1919

2020
const cache = new LRU<"kernel_data", KernelSpec[]>({
2121
ttl: 15 * 1000,
@@ -44,35 +44,39 @@ function spec2language(spec): string {
4444
}
4545
}
4646

47-
export async function get_kernel_data(): Promise<KernelSpec[]> {
48-
let x = cache.get("kernel_data");
49-
if (x != null) {
50-
return x;
51-
}
52-
const kernel_data = await findAll();
53-
const v: KernelSpec[] = [];
54-
for (const kernel in kernel_data) {
55-
const value = kernel_data[kernel];
56-
v.push({
57-
name: kernel.toLowerCase(),
58-
display_name: value.spec.display_name,
59-
language: spec2language(value.spec),
60-
// @ts-ignore
61-
interrupt_mode: value.spec.interrupt_mode,
62-
env: value.spec.env ?? {},
63-
// @ts-ignore
64-
metadata: value.spec.metadata,
65-
// kernelspecs incorrectly calls it resources_dir instead of resource_dir.
66-
// See https://github.com/nteract/kernelspecs/issues/25
67-
// @ts-ignore
68-
resource_dir: value.resource_dir ?? value.resources_dir,
69-
argv: value.spec.argv,
70-
});
71-
}
72-
v.sort(field_cmp("display_name"));
73-
cache.set("kernel_data", v);
74-
return v;
75-
}
47+
// this is very expensive and can get called many times at once before
48+
// the cache is set, which is very bad... so reuseInFlight.
49+
export const get_kernel_data = reuseInFlight(
50+
async (): Promise<KernelSpec[]> => {
51+
let x = cache.get("kernel_data");
52+
if (x != null) {
53+
return x;
54+
}
55+
const kernel_data = await findAll();
56+
const v: KernelSpec[] = [];
57+
for (const kernel in kernel_data) {
58+
const value = kernel_data[kernel];
59+
v.push({
60+
name: kernel.toLowerCase(),
61+
display_name: value.spec.display_name,
62+
language: spec2language(value.spec),
63+
// @ts-ignore
64+
interrupt_mode: value.spec.interrupt_mode,
65+
env: value.spec.env ?? {},
66+
// @ts-ignore
67+
metadata: value.spec.metadata,
68+
// kernelspecs incorrectly calls it resources_dir instead of resource_dir.
69+
// See https://github.com/nteract/kernelspecs/issues/25
70+
// @ts-ignore
71+
resource_dir: value.resource_dir ?? value.resources_dir,
72+
argv: value.spec.argv,
73+
});
74+
}
75+
v.sort(field_cmp("display_name"));
76+
cache.set("kernel_data", v);
77+
return v;
78+
},
79+
);
7680

7781
export async function getLanguage(kernelName: string): Promise<string> {
7882
const kernelSpec = await get_kernel_data_by_name(kernelName);

0 commit comments

Comments
 (0)