Graceful handling of task cancellation

This commit is contained in:
Sipke Schoorstra 2023-04-13 20:35:55 +02:00
parent 5c3a016140
commit 98e0b4ae5f
3 changed files with 43 additions and 12 deletions

View file

@ -172,17 +172,7 @@ public abstract class SendHttpRequestBase : Activity<HttpResponseMessage>
/// <inheritdoc />
protected override async ValueTask ExecuteAsync(ActivityExecutionContext context)
{
var request = PrepareRequest(context);
var httpClientFactory = context.GetRequiredService<IHttpClientFactory>();
var httpClient = httpClientFactory.CreateClient(nameof(SendHttpRequestBase));
var cancellationToken = context.CancellationToken;
var response = await httpClient.SendAsync(request, cancellationToken);
var parsedContent = await ParseContentAsync(context, response.Content);
context.Set(Result, response);
context.Set(ParsedContent, parsedContent);
await HandleResponseAsync(context, response);
await TrySendAsync(context);
}
/// <summary>
@ -190,6 +180,28 @@ public abstract class SendHttpRequestBase : Activity<HttpResponseMessage>
/// </summary>
protected abstract ValueTask HandleResponseAsync(ActivityExecutionContext context, HttpResponseMessage response);
private async Task TrySendAsync(ActivityExecutionContext context)
{
var request = PrepareRequest(context);
var httpClientFactory = context.GetRequiredService<IHttpClientFactory>();
var httpClient = httpClientFactory.CreateClient(nameof(SendHttpRequestBase));
var cancellationToken = context.CancellationToken;
try
{
var response = await httpClient.SendAsync(request, cancellationToken);
var parsedContent = await ParseContentAsync(context, response.Content);
context.Set(Result, response);
context.Set(ParsedContent, parsedContent);
await HandleResponseAsync(context, response);
}
catch (TaskCanceledException e)
{
context.JournalData.Add("Cancelled", true);
}
}
private async Task<object?> ParseContentAsync(ActivityExecutionContext context, HttpContent httpContent)
{
if (!HasContent(httpContent))

View file

@ -5,13 +5,21 @@ using Elsa.Workflows.Runtime.Notifications;
namespace Elsa.Http.Handlers;
/// <summary>
/// A handler that updates the route table.
/// </summary>
public class UpdateRouteTable :
INotificationHandler<WorkflowTriggersIndexed>,
INotificationHandler<WorkflowBookmarksIndexed>
{
private readonly IRouteTable _routeTable;
/// <summary>
/// Initializes a new instance of the <see cref="UpdateRouteTable"/> class.
/// </summary>
public UpdateRouteTable(IRouteTable routeTable) => _routeTable = routeTable;
/// <inheritdoc />
public Task HandleAsync(WorkflowTriggersIndexed notification, CancellationToken cancellationToken)
{
_routeTable.RemoveRoutes(notification.IndexedWorkflowTriggers.RemovedTriggers);
@ -20,6 +28,7 @@ public class UpdateRouteTable :
return Task.CompletedTask;
}
/// <inheritdoc />
public Task HandleAsync(WorkflowBookmarksIndexed notification, CancellationToken cancellationToken)
{
_routeTable.RemoveRoutes(notification.IndexedWorkflowBookmarks.RemovedBookmarks);

View file

@ -6,6 +6,7 @@ using Elsa.Workflows.Runtime.Contracts;
using Elsa.Workflows.Runtime.Middleware.Activities;
using Elsa.Workflows.Runtime.Models;
using Elsa.Workflows.Runtime.Models.Requests;
using Microsoft.Extensions.Logging;
namespace Elsa.Workflows.Runtime.Services;
@ -21,6 +22,7 @@ public class DefaultBackgroundActivityInvoker : IBackgroundActivityInvoker
private readonly IVariablePersistenceManager _variablePersistenceManager;
private readonly IActivityInvoker _activityInvoker;
private readonly IServiceProvider _serviceProvider;
private readonly ILogger _logger;
/// <summary>
/// Initializes a new instance of the <see cref="DefaultBackgroundActivityInvoker"/> class.
@ -32,7 +34,8 @@ public class DefaultBackgroundActivityInvoker : IBackgroundActivityInvoker
IWorkflowExecutionContextFactory workflowExecutionContextFactory,
IVariablePersistenceManager variablePersistenceManager,
IActivityInvoker activityInvoker,
IServiceProvider serviceProvider)
IServiceProvider serviceProvider,
ILogger<DefaultBackgroundActivityInvoker> logger)
{
_workflowRuntime = workflowRuntime;
_workflowDispatcher = workflowDispatcher;
@ -41,6 +44,7 @@ public class DefaultBackgroundActivityInvoker : IBackgroundActivityInvoker
_variablePersistenceManager = variablePersistenceManager;
_activityInvoker = activityInvoker;
_serviceProvider = serviceProvider;
_logger = logger;
}
/// <inheritdoc />
@ -118,6 +122,12 @@ public class DefaultBackgroundActivityInvoker : IBackgroundActivityInvoker
}
};
if(cancellationToken.IsCancellationRequested)
{
_logger.LogInformation("Background execution for activity {ActivityNodeId} was canceled", activityNodeId);
return;
}
await _workflowDispatcher.DispatchAsync(dispatchRequest, cancellationToken);
}
}