From 3c757ef5c10bf9abbd58af81770f3b3166db4074 Mon Sep 17 00:00:00 2001 From: Tom Longhurst <30480171+thomhurst@users.noreply.github.com> Date: Mon, 22 Dec 2025 12:02:51 +0000 Subject: [PATCH] More Robust Global Timeout Cancellation --- TUnit.Core/EngineCancellationToken.cs | 29 +++++++++++++-------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/TUnit.Core/EngineCancellationToken.cs b/TUnit.Core/EngineCancellationToken.cs index 395cc7c5dd..ea3250db16 100644 --- a/TUnit.Core/EngineCancellationToken.cs +++ b/TUnit.Core/EngineCancellationToken.cs @@ -14,8 +14,7 @@ public class EngineCancellationToken : IDisposable /// Gets the cancellation token. /// public CancellationToken Token { get; private set; } - - private CancellationTokenSource? _forcefulExitCts; + private volatile bool _forcefulExitStarted; /// @@ -27,6 +26,8 @@ internal void Initialise(CancellationToken cancellationToken) CancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); Token = CancellationTokenSource.Token; + Token.Register(_ => Cancel(), this); + // Console.CancelKeyPress is not supported on browser platforms #if NET5_0_OR_GREATER if (!OperatingSystem.IsBrowser()) @@ -38,8 +39,16 @@ internal void Initialise(CancellationToken cancellationToken) } #endif } - + private void OnCancelKeyPress(object? sender, ConsoleCancelEventArgs e) + { + Cancel(); + + // Prevent the default behavior (immediate termination) + e.Cancel = true; + } + + private void Cancel() { // Cancel the test execution if (!CancellationTokenSource.IsCancellationRequested) @@ -51,14 +60,9 @@ private void OnCancelKeyPress(object? sender, ConsoleCancelEventArgs e) if (!_forcefulExitStarted) { _forcefulExitStarted = true; - - // Cancel any previous forceful exit timer - _forcefulExitCts?.Cancel(); - _forcefulExitCts?.Dispose(); - _forcefulExitCts = new CancellationTokenSource(); - + // Start a new forceful exit timer - _ = Task.Delay(TimeSpan.FromSeconds(10), _forcefulExitCts.Token).ContinueWith(t => + _ = Task.Delay(TimeSpan.FromSeconds(30), CancellationToken.None).ContinueWith(t => { if (!t.IsCanceled) { @@ -67,9 +71,6 @@ private void OnCancelKeyPress(object? sender, ConsoleCancelEventArgs e) } }, TaskScheduler.Default); } - - // Prevent the default behavior (immediate termination) - e.Cancel = true; } private void OnProcessExit(object? sender, EventArgs e) @@ -102,8 +103,6 @@ public void Dispose() #if NET5_0_OR_GREATER } #endif - _forcefulExitCts?.Cancel(); - _forcefulExitCts?.Dispose(); CancellationTokenSource.Dispose(); } }