Canceling job always results in process kill when running as a Windows service

Triage note. This report describes two defects with separate causes. The third section, "Running as a service with legacy process strategy", is split out to #39720 (closed) and is fixed separately.

  • #39720 (closed) — with the flag set, the event reaches the process, then the runner force-kills it anyway. The runner reads the failure to restore its own console as a failed termination. Fix: !7275 (merged)
  • This issue — on the default path the event is never delivered, because a runner started by the Service Control Manager holds no console. Fix: !7276 (merged), which routes the event through the console of the job process rather than one the runner does not have.

Both are in 19.4. #39721 (closed) adds the missing test coverage. #39684 (closed) tracks the set.

The report below is unchanged.


When running gitlab-runner as a Windows service, the runner process has no console, causing the graceful termination mechanism(s) to fail.

  • gitlab-runner version: 17.11.1 (but newer versions behave the same)
  • executor = "shell"
  • shell = "pwsh"
  • Windows version: 10.0.26100.7840

Running interactively

If I run gitlab-runner from a console, there is a console, and the application being run is terminated gracefully.

Starting test run...
Canceling test run...
The test run was canceled.
WARNING: script canceled externally (UI, API)

(WARNING messages come from the runner; other messages come from the application being run by the script.)

Running as a service

If I run gitlab-runner as a Windows service, there is no console, the application being run does not receive a signal to terminate, and the runner always kills the application immediately after it determines that graceful termination has failed.

Starting test run...
WARNING: Failed to terminate process: 1 error occurred:
	* failed to send Ctrl-Break event to process being terminated: The handle is invalid.
WARNING: script canceled externally (UI, API)

GenerateConsoleCtrlEvent fails.

Running as a service with legacy process strategy

If I run gitlab-runner as a Windows service and configure the runner with FF_USE_WINDOWS_LEGACY_PROCESS_STRATEGY = true, there is no console, but the application being run does receive a signal to terminate gracefully and may terminate gracefully if it manages to do so before the runner kills it immediately after (incorrectly) determining that graceful termination has failed.

Starting test run...
WARNING: Failed to terminate process: 1 error occurred:
	* failed to attach the runner process to the console of its parent process: The handle is invalid.
Canceling test run...
The test run was canceled.
WARNING: script canceled externally (UI, API)

AttachConsole fails to reattach to the console of the runner's parent process.

Interestingly, AttachConsole does not fail to attach to the console of the process running the application, so this mechanism would work if it didn't go on to kill the process immediately afterward.

Edited by Lachlan Grant