Skip to content

Worker rules: allow cmdlets, check by default, refuse scriptblock job values - #5

Merged
HalRiveria merged 3 commits into
mainfrom
rework/worker-rules
Oct 28, 2026
Merged

HalRiveria merged 3 commits into
mainfrom
rework/worker-rules

Conversation

@HalRiveria-Bot

@HalRiveria-Bot HalRiveria-Bot commented Oct 28, 2026 •

Copy link
Copy Markdown
Collaborator

What was wrong. The README's rule 2 banned cmdlets in worker code, blaming a race in first-time cmdlet setup. Stress testing doesn't back that up: thousands of rounds of 8 workers calling cmdlets at the same instant never hung. The real cause is a scriptblock running on another runspace's thread (PowerShell/PowerShell#4003). With an inner scriptblock (Where-Object { }, a nested delegate) that deadlocks, and even without one it can crash the process. A scriptblock passed in as a job value is the same case and the checker couldn't see it: 8 workers running one passed from the main thread broke 88 of 90 stress runs, while the same code passed as text and rebuilt with [scriptblock]::Create ran clean in 30 of 30.

What changed.

  • Test-PkWorkerSafety drops the Cmdlet rule. DelegateCast messages say "hang or crash".
  • The delegate check also flags a variable assigned a scriptblock (or { }.GetNewClosure()) when it's passed to a .NET method or constructor, e.g. [System.Lazy[object]]::new($factory).
  • Functions from a module (e.g. Get-FileHash, a script function in 5.1) are no longer reported as unshared functions; they autoload in the worker.
  • Invoke-PkRunspaceJobs runs the safety check by default (-CheckWorkerSafety:$false turns it off). Existing -CheckWorkerSafety calls still work.
  • With the check on, a job value that is a scriptblock, or holds one in an array or hashtable, is refused: before any worker starts for -JobParams, per job for -NextJobProvider. The error names the job and key and gives the pass-as-text workaround.
  • README: "The two rules", the real mechanism with the #4003 link, rewritten cmdlet FAQ answers, and the hashing example now uses Get-FileHash.

Breaking: worker code with delegates, or jobs carrying scriptblocks, that used to launch is now refused unless the check is turned off. Intended for v2.0.

Testing. Harness: 179 assertions pass. The new assertions (cmdlets pass the check, the check runs unasked, scriptblock job values refused for a fixed list / inside an array / from -NextJobProvider) fail against main's kit (5 failures); the two scriptblock-variable assertions fail against the first commit's kit. The README's hashing example was run as written.

🤖 Generated with Claude Code

HalRiveria and others added 3 commits October 28, 2026 02:53
… values

Cmdlets in workers don't hang. The hangs blamed on them came from
scriptblocks running on another runspace's thread (PowerShell issue
#4003): a delegate, or a scriptblock passed in as a job value.

- Test-PkWorkerSafety no longer flags cmdlets. DelegateCast messages
  say "hang or crash" instead of "deadlock".
- Functions from a module (Get-FileHash in 5.1) no longer count as
  unshared functions; they autoload in the worker.
- Invoke-PkRunspaceJobs runs the safety check by default;
  -CheckWorkerSafety:$false turns it off.
- With the check on, a job value that is (or directly holds) a
  scriptblock is refused: before any worker starts for -JobParams,
  per job for -NextJobProvider. The message gives the pass-as-text
  workaround.
- README: two rules instead of three, the real mechanism, new FAQ
  answers, and the hashing example uses Get-FileHash.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Test-PkWorkerSafety only caught a scriptblock written directly in a
.NET call. It now also flags a variable assigned a scriptblock literal
(or { }.GetNewClosure()) in the same code when that variable is passed
to a .NET method or constructor, e.g. [System.Lazy[object]]::new($f).
.ForEach()/.Where() stay exempt. README lists comparers and event/task
callbacks among the delegate cases.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@HalRiveria
HalRiveria merged commit b1468cc into main Oct 28, 2026
1 check passed
@HalRiveria
HalRiveria deleted the rework/worker-rules branch October 28, 2026 07:08
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