Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
# [vNext]

## Improvements:
* Refactor: Introduce virtual timeout properties FormattersBase class to allow individual formatters to override the defaults

## Bug fixes:

*Contributors of this release (in alphabetical order):*
*Contributors of this release (in alphabetical order):* @clrudolphi

# v3.3.3 - 2026-01-27

Expand Down
14 changes: 12 additions & 2 deletions Reqnroll/Formatters/FormatterBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,16 @@ public abstract class FormatterBase : ICucumberMessageFormatter, IDisposable

public string Name => _pluginName;

/// <summary>
/// Gets the timeout duration to wait for formatter task completion during disposal.
/// </summary>
protected virtual TimeSpan DisposeTimeout => TimeSpan.FromSeconds(15);

/// <summary>
/// Gets the timeout duration to wait after cancellation during disposal.
/// </summary>
protected virtual TimeSpan DisposeCancellationTimeout => TimeSpan.FromSeconds(15);

protected FormatterBase(IFormattersConfigurationProvider configurationProvider, IFormatterLog logger, string pluginName)
{
_configurationProvider = configurationProvider;
Expand Down Expand Up @@ -134,7 +144,7 @@ public virtual void Dispose()
Logger.WriteMessage($"DEBUG: Formatters: Dispose is waiting on the formatter task {Name}.");
// In this situation, the TestEngine is shutting down and has called Dispose on the global container.
// Forcing the Dispose to wait until the formatter has had a chance to complete.
var timeoutTask = Task.Delay(TimeSpan.FromSeconds(15));
var timeoutTask = Task.Delay(DisposeTimeout);
var finishedTask = Task.WhenAny(timeoutTask, _formatterTask).GetAwaiter().GetResult();
if (finishedTask == timeoutTask)
{
Expand All @@ -151,7 +161,7 @@ public virtual void Dispose()
_logger.WriteMessage($"DEBUG: Formatters:PluginBase.Dispose - cancellation message can't be sent as the collection is closed.");
}
_logger.WriteMessage($"DEBUG: Formatters.PluginBase.Dispose - waiting again after cancellation.");
timeoutTask = Task.Delay(TimeSpan.FromSeconds(15));
timeoutTask = Task.Delay(DisposeCancellationTimeout);
finishedTask = Task.WhenAny(timeoutTask, _formatterTask).GetAwaiter().GetResult();
if (finishedTask == timeoutTask)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ private class TestFileWritingFormatter : FileWritingFormatterBase
public bool FinalizeInitializationCalled = false;
public Stream? LastStream;

protected override TimeSpan DisposeTimeout => TimeSpan.FromMilliseconds(100);
protected override TimeSpan DisposeCancellationTimeout => TimeSpan.FromMilliseconds(100);

public TestFileWritingFormatter(IFormattersConfigurationProvider config, IFormatterLog logger, IFileSystem fileSystem)
: base(config, logger, fileSystem, "testPlugin", ".txt", "default.txt") { }

Expand Down
2 changes: 2 additions & 0 deletions Tests/Reqnroll.RuntimeTests/Formatters/FormatterBaseTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ private class TestFormatter : FormatterBase
public bool ReportInitializedCalled = false;
public bool CloseAsyncCalled = false;
public bool CompleteWriterOnLaunchInner = false;
protected override TimeSpan DisposeTimeout => TimeSpan.FromMilliseconds(100);
protected override TimeSpan DisposeCancellationTimeout => TimeSpan.FromMilliseconds(100);

public TestFormatter(IFormattersConfigurationProvider config, IFormatterLog logger, string name)
: base(config, logger, name) { }
Expand Down
Loading