























@@ -522,10 +522,9 @@ describe("check-extension-package-tsc-boundary", () => {
522522tempRoots.add(root);
523523const childPidPath = path.join(root, "child.pid");
524524let childPid = 0;
525-const childScript = [
526-"process.on('SIGTERM', () => {});",
527-"setInterval(() => {}, 1000);",
528-].join("");
525+const childScript = ["process.on('SIGTERM', () => {});", "setInterval(() => {}, 1000);"].join(
526+"",
527+);
529528const parentScript = [
530529"const { spawn } = require('node:child_process');",
531530"const fs = require('node:fs');",
@@ -535,16 +534,11 @@ describe("check-extension-package-tsc-boundary", () => {
535534].join("");
536535537536try {
538-const failurePromise = runNodeStepAsync(
539-"hung-step-group",
540-["--eval", parentScript],
541-100,
542-{
543-spawnImpl(command: string, args: string[], options: unknown) {
544-return spawn(command, args, options as Parameters<typeof spawn>[2]);
545-},
537+const failurePromise = runNodeStepAsync("hung-step-group", ["--eval", parentScript], 100, {
538+spawnImpl(command: string, args: string[], options: unknown) {
539+return spawn(command, args, options as Parameters<typeof spawn>[2]);
546540},
547-).then(
541+}).then(
548542() => {
549543throw new Error("expected hung-step-group to time out");
550544},
@@ -592,6 +586,72 @@ describe("check-extension-package-tsc-boundary", () => {
592586expect(Date.now() - startedAt).toBeLessThan(abortBudgetMs);
593587}, 45_000);
594588589+it.skipIf(process.platform === "win32")(
590+"force-kills aborted async node step process groups",
591+async () => {
592+const { rootDir: root } = createTempExtensionRoot("abort-group");
593+const childPidPath = path.join(root, "child.pid");
594+let childPid = 0;
595+const childScript = ["process.on('SIGTERM', () => {});", "setInterval(() => {}, 1000);"].join(
596+"",
597+);
598+const parentScript = [
599+"const { spawn } = require('node:child_process');",
600+"const fs = require('node:fs');",
601+`const child = spawn(process.execPath, ['-e', ${JSON.stringify(childScript)}], { stdio: 'ignore' });`,
602+`fs.writeFileSync(${JSON.stringify(childPidPath)}, String(child.pid));`,
603+"process.on('SIGTERM', () => process.exit(0));",
604+"setInterval(() => {}, 1000);",
605+].join("");
606+const failAfterSiblingStartsScript = [
607+"const fs = require('node:fs');",
608+`const childPidPath = ${JSON.stringify(childPidPath)};`,
609+"const deadlineAt = Date.now() + 2_000;",
610+"const wait = () => {",
611+" if (fs.existsSync(childPidPath)) {",
612+" setTimeout(() => process.exit(2), 150);",
613+" return;",
614+" }",
615+" if (Date.now() >= deadlineAt) {",
616+" process.exit(2);",
617+" return;",
618+" }",
619+" setTimeout(wait, 10);",
620+"};",
621+"wait();",
622+].join("");
623+624+try {
625+const command = runNodeStepsWithConcurrency(
626+[
627+{
628+label: "fail-fast",
629+args: ["--eval", failAfterSiblingStartsScript],
630+timeoutMs: 5_000,
631+},
632+{
633+label: "aborted-step-group",
634+args: ["--eval", parentScript],
635+timeoutMs: 60_000,
636+},
637+],
638+2,
639+);
640+641+await waitForFile(childPidPath, 2_000);
642+childPid = Number.parseInt(fs.readFileSync(childPidPath, "utf8"), 10);
643+expect(isProcessAlive(childPid)).toBe(true);
644+645+await expect(command).rejects.toThrow("fail-fast");
646+await waitForDead(childPid, 2_000);
647+} finally {
648+if (childPid && isProcessAlive(childPid)) {
649+process.kill(childPid, "SIGKILL");
650+}
651+}
652+},
653+);
654+595655it("passes successful step timing metadata to onSuccess handlers", async () => {
596656const elapsedTimes: number[] = [];
597657此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。