This PR adds support for creating a timeout behavior.
This PR is in direct response to #1056 , and the long discussion of #592. This was an older issue turned to discussion. I have solved the issue with the below implementation.
The below implementation modifies the RequestHandlerDelegate to take an optional CancellationToken. I also modify the RequestHandlerWrapperImpl to match the delegate so the casting still works. Then I modify the Aggregation to pass the token into the handle method for the next handler.
Usage:
public class TimeoutBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
where TRequest : notnull
{
public async Task<TResponse> Handle(TRequest request, RequestHandlerDelegate<TResponse> next, CancellationToken cancellationToken)
{
using (var cts = new CancellationTokenSource(someTimeoutDuration))
{
return await next(cts.Token);
}
}
}
Test Handler:
public class TimeoutRequestHandler : IRequestHandler<TimeoutRequest>
{
private readonly Dependency _dependency;
public TimeoutRequestHandler(Dependency dependency) => _dependency = dependency;
public async Task Handle(TimeoutRequest request, CancellationToken cancellationToken)
{
await Task.Delay(someTimeThatIsLongerThanTheTimeoutDuration, cancellationToken);
_dependency.Called = true;
}
}
Unit Test:
[Fact]
public async Task TimeoutBehavior_Void_Should_Cancel_Long_Running_Task_And_Throw_Exception()
{
var request = new TimeoutRequest();
var exception = await Should.ThrowAsync<TaskCanceledException>(() => _mediator.Send(request));
exception.ShouldNotBeNull();
exception.ShouldBeAssignableTo<TaskCanceledException>();
_dependency.Called.ShouldBeFalse();
}
This PR adds support for creating a timeout behavior.
This PR is in direct response to #1056 , and the long discussion of #592. This was an older issue turned to discussion. I have solved the issue with the below implementation.
The below implementation modifies the
RequestHandlerDelegate
to take an optionalCancellationToken
. I also modify theRequestHandlerWrapperImpl
to match the delegate so the casting still works. Then I modify the Aggregation to pass the token into the handle method for the next handler.Usage:
Test Handler:
Unit Test: