|
1 | 1 | // @effect-diagnostics nodeBuiltinImport:off - verifies isolated native worker processes and their exit events. |
| 2 | +import * as NodeFS from "node:fs"; |
| 3 | +import * as NodeOS from "node:os"; |
| 4 | +import * as NodePath from "node:path"; |
| 5 | + |
2 | 6 | import { expect, it } from "vite-plus/test"; |
3 | 7 |
|
4 | 8 | import { loadNativeSpeechModel } from "./native.ts"; |
@@ -155,6 +159,37 @@ it("kills a hung streaming feed without waiting for native cleanup", async () => |
155 | 159 | await model.dispose(); |
156 | 160 | await rejected; |
157 | 161 | }); |
| 162 | + |
| 163 | +it("skips process exit teardown when the backend dies during native inference", async () => { |
| 164 | + const directory = NodeFS.mkdtempSync(NodePath.join(NodeOS.tmpdir(), "t3code-speech-orphan-")); |
| 165 | + const marker = NodePath.join(directory, "exit-teardown"); |
| 166 | + // The exit hook stands in for native atexit teardown; the interval for the threadpool call. |
| 167 | + const model = await loadNativeSpeechModel( |
| 168 | + "unused.gguf", |
| 169 | + new AbortController().signal, |
| 170 | + streamingFixture(`async () => { |
| 171 | + const { writeFileSync } = process.getBuiltinModule("node:fs"); |
| 172 | + process.once("exit", () => writeFileSync(${JSON.stringify(marker)}, "ran")); |
| 173 | + setInterval(() => {}, 1 << 30); |
| 174 | + process.disconnect(); |
| 175 | + return await new Promise(() => {}); |
| 176 | + }`), |
| 177 | + ); |
| 178 | + try { |
| 179 | + await model.begin({ timestamps: "none" }, false); |
| 180 | + await expect(model.feed(new Float32Array(512).fill(0.25))).rejects.toThrow( |
| 181 | + "Speech process exited", |
| 182 | + ); |
| 183 | + expect( |
| 184 | + NodeFS.existsSync(marker), |
| 185 | + "orphaned worker ran exit teardown while native inference was in flight", |
| 186 | + ).toBe(false); |
| 187 | + } finally { |
| 188 | + await model.dispose(); |
| 189 | + NodeFS.rmSync(directory, { recursive: true, force: true }); |
| 190 | + } |
| 191 | +}); |
| 192 | + |
158 | 193 | const vadFixture = ({ |
159 | 194 | streaming = false, |
160 | 195 | failVad = false, |
|
0 commit comments