Skip to content

Stop a -ResultHandler without a closure from looping forever - #19

Merged
HalRiveria merged 2 commits into
mainfrom
fix/runspace-results-name
Oct 29, 2026
Merged

HalRiveria merged 2 commits into
mainfrom
fix/runspace-results-name

Conversation

@HalRiveria-Bot

Copy link
Copy Markdown
Collaborator

What was wrong

A -ResultHandler built without .GetNewClosure() sees Invoke-PkRunspaceJobs' local variables by dynamic scope. The worker output being fed to the handler sat in a local named $results. So a handler doing the natural thing, $results.Add($r), added to the collection the kit was looping over, and the run never ended: no error, one core busy, the caller's own $results empty. Under Invoke-PkRun, Ctrl+C only sets the abort flag, which that loop never checks, so it couldn't be stopped.

The same loop is in the abort-drain path (Receive-PkCompletedHandles). And a -JobCrashedHandler doing $results.Add($err) hit the kit's $null instead of the caller's list; the error was swallowed, so the caller's list just stayed empty.

Reproduced on Windows PowerShell 5.1 and PowerShell 7.

What changed

  • ParallelKit.ps1: renamed that local to $pkWorkerOutput in both places, with a comment in each naming the other.
  • ParallelKit.Harness.ps1: three checks, all with closure-less callbacks:
    • -ResultHandler doing $results.Add makes exactly one call per result and reaches the caller's list (a 20-call guard throws instead of hanging the harness if it regresses);
    • the same during an abort drain, asserting the drain really collected the results;
    • -JobCrashedHandler doing $results.Add reaches the caller's list.

This is a narrow fix for the one name that caused a hang. Callbacks without a closure can still see the kit's other locals (for example $outcome); .GetNewClosure() remains the documented way to build them.

Testing

  • The three new checks fail without the fix on 5.1 and 7 (3 FAILED, 225 passed). The drain check also fails when only the main loop is fixed, so it covers the drain copy.
  • With the fix: ALL PASSED (228 assertions) on 5.1 and 7.

🤖 Generated with Claude Code

HalRiveria and others added 2 commits October 29, 2026 09:28
A -ResultHandler built without .GetNewClosure() sees Invoke-PkRunspaceJobs'
locals by dynamic scope. The worker output it was being fed sat in a local
named $results, so a handler doing $results.Add($r) added to the collection
the kit was looping over, and the run never ended. Under Invoke-PkRun, Ctrl+C
couldn't stop it either. The abort-drain path had the same loop, and a
-JobCrashedHandler doing $results.Add($err) hit the kit's $null instead of
the caller's list, with the error swallowed.

Rename that local in both places so these callbacks reach the caller's own
$results. Harness checks cover the normal path, the abort drain and the
crash handler; all three fail without the fix.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@HalRiveria
HalRiveria merged commit bb3a4a2 into main Oct 29, 2026
2 checks passed
@HalRiveria
HalRiveria deleted the fix/runspace-results-name branch October 29, 2026 13:47
@HalRiveria-Bot HalRiveria-Bot mentioned this pull request Oct 29, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants