Describe the bug
On Windows, cancel: on one background step also interrupts every other step that is running at that moment. The step you didn't cancel gets the same Ctrl+C and fails. On Linux only the cancelled step is affected.
To Reproduce
Minimal public repro: https://github.com/raymond-UI/runner-background-cancel-repro (workflow, run)
- name: Target
id: target
background: true
run: node -e "process.on('SIGINT',()=>{console.log('target got SIGINT');process.exit(0)}); setInterval(()=>{},1000)"
- name: Bystander
id: bystander
background: true
run: node -e "process.on('SIGINT',()=>{console.log('bystander got SIGINT');process.exit(3)}); setTimeout(()=>console.log('bystander finished on its own'),20000)"
- shell: bash
run: sleep 3
- cancel: target
- wait: bystander
Expected behavior
Only Target is cancelled. Bystander keeps running and finishes on its own after 20 s, as it does on ubuntu-latest.
Runner Version and Platform
2.337.0, GitHub-hosted windows-latest. Also reproduced on a self-hosted Windows 11 runner on 2.337.0.
What's not working?
|
runs |
bystander survives |
windows-latest |
5 |
0 |
ubuntu-latest |
5 |
5 |
Likely cause, from the source:
ScriptHandler passes inheritConsoleHandler: !Retain_Default_Encoding, which is true by default. So ProcessInvoker starts every script step with CreateNoWindow = false, and all steps share the worker's console.
ProcessInvoker.SendCtrlSignal does AttachConsole(_proc.Id), then GenerateConsoleCtrlEvent(signal, 0). Process group 0 means every process attached to that console, so every running step gets the event.
- The Ctrl+Break fallback after 7.5 s has the same reach. On our self-hosted runner, where the Ctrl+C was ignored, the bystander's pwsh dropped into its debugger and the step failed.
This was harmless when cancel only ran for the whole job. With background steps it becomes reachable. Starting each step in its own process group (CREATE_NEW_PROCESS_GROUP) and signalling that group, rather than group 0, would limit the event to the cancelled step's tree.
Job Log Output
windows-latest, attempt 1:
05:40:55.4893636Z Cancelling background step(s): Target
05:40:55.5060473Z bystander got SIGINT
05:40:55.5060482Z target got SIGINT
05:40:55.5663204Z Finished cancelling background step(s).
05:40:55.5663643Z Target: Canceled
05:40:55.5888725Z ##[error]Process completed with exit code 1.
05:40:55.7343108Z Waiting for background step(s) to complete: Bystander
05:40:55.7354311Z Finished waiting for background step(s).
05:40:55.7354649Z Bystander: Failed
Describe the bug
On Windows,
cancel:on one background step also interrupts every other step that is running at that moment. The step you didn't cancel gets the same Ctrl+C and fails. On Linux only the cancelled step is affected.To Reproduce
Minimal public repro: https://github.com/raymond-UI/runner-background-cancel-repro (workflow, run)
Expected behavior
Only
Targetis cancelled.Bystanderkeeps running and finishes on its own after 20 s, as it does onubuntu-latest.Runner Version and Platform
2.337.0, GitHub-hosted
windows-latest. Also reproduced on a self-hosted Windows 11 runner on 2.337.0.What's not working?
windows-latestubuntu-latestLikely cause, from the source:
ScriptHandlerpassesinheritConsoleHandler: !Retain_Default_Encoding, which is true by default. SoProcessInvokerstarts every script step withCreateNoWindow = false, and all steps share the worker's console.ProcessInvoker.SendCtrlSignaldoesAttachConsole(_proc.Id), thenGenerateConsoleCtrlEvent(signal, 0). Process group0means every process attached to that console, so every running step gets the event.This was harmless when cancel only ran for the whole job. With background steps it becomes reachable. Starting each step in its own process group (
CREATE_NEW_PROCESS_GROUP) and signalling that group, rather than group 0, would limit the event to the cancelled step's tree.Job Log Output
windows-latest, attempt 1: