perf(pi-natives): optimized pipe I/O to use async instead of blocking workers

- Replaced blocking Tokio worker with non-blocking async I/O for pipe reading to prevent stalling the runtime when child processes keep pipes open.
- Refactored background job termination to use process group and process tree APIs instead of deprecated signal parsing, improving reliability across Unix and Windows.
- Added non-blocking pipe registration and fcntl-based flag management for Unix platforms to enable efficient async I/O without blocking workers.
- Added test case verifying read_output cancellation before pipe EOF to ensure proper cleanup behavior.
This commit is contained in:
can1357
2026-04-01 20:46:21 +02:00
parent 9281e6b50e
commit 9d5508980f
3 changed files with 214 additions and 36 deletions
+24
View File
@@ -3,6 +3,7 @@ import * as fs from "node:fs/promises";
import * as os from "node:os";
import * as path from "node:path";
import {
executeShell,
FileType,
fuzzyFind,
type GlobMatch,
@@ -385,6 +386,29 @@ describe("pi-natives", () => {
}
});
});
describe("shell", () => {
it("should time out background workloads without leaving delayed writers behind", async () => {
if (process.platform === "win32") {
return;
}
const markerPath = path.join(testDir, "shell-timeout-marker.txt");
const markerEscaped = markerPath.replace(/'/g, "'\\''");
await fs.rm(markerPath, { force: true });
const result = await executeShell({
command: `{ sleep 2; echo done > '${markerEscaped}'; } & sleep 10`,
cwd: testDir,
timeoutMs: 100,
});
expect(result.timedOut).toBe(true);
await Bun.sleep(3000);
expect(await Bun.file(markerPath).exists()).toBe(false);
});
});
describe("htmlToMarkdown", () => {
it("should convert basic HTML to markdown", async () => {
const html = "<h1>Hello World</h1><p>This is a paragraph.</p>";