fix(eval): resolved JS/Python resets by awaiting in-flight operations

- Coalesced concurrent JS and Python reset requests by awaiting in-flight promises instead of throwing.
- Aligned non-reset execution calls to wait for in-progress resets before running on a recreated session.
This commit is contained in:
can1357
2026-06-08 02:04:59 +02:00
parent 49aa6e5839
commit 088fb7fb75
3 changed files with 68 additions and 22 deletions
@@ -119,4 +119,27 @@ describe("executePython lifecycle", () => {
expect(kernel.execute).toHaveBeenCalledTimes(0);
expect(kernelNext.execute).toHaveBeenCalledTimes(2);
});
it("coalesces concurrent reset requests instead of throwing 'reset already in progress'", async () => {
// Two cells from the same session asking for reset in flight at once
// previously crashed the second one with "Python kernel reset already
// in progress" — the user reported this as eval returning only the
// status line and no executed output. The executor now waits for the
// in-flight reset and then proceeds.
const kernelA = new FakeKernel(OK_RESULT);
const kernelB = new FakeKernel(OK_RESULT);
vi.spyOn(pythonKernel, "checkPythonKernelAvailability").mockResolvedValue({ ok: true });
vi.spyOn(pythonKernel.PythonKernel, "start")
.mockResolvedValueOnce(kernelA as unknown as pythonKernel.PythonKernel)
.mockResolvedValueOnce(kernelB as unknown as pythonKernel.PythonKernel);
// Seed a live session that both reset cells will tear down.
await executePython("1 + 1", { kernelMode: "session", sessionId: "coalesce", cwd: getProjectDir() });
const [r1, r2] = await Promise.all([
executePython("2 + 2", { kernelMode: "session", sessionId: "coalesce", reset: true, cwd: getProjectDir() }),
executePython("3 + 3", { kernelMode: "session", sessionId: "coalesce", reset: true, cwd: getProjectDir() }),
]);
expect(r1.exitCode).toBe(0);
expect(r2.exitCode).toBe(0);
});
});