parent
6b380e86f4
commit
974b3c2df2
7
Elsa.sln
7
Elsa.sln
|
|
@ -216,6 +216,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.Persistence.EntityFram
|
|||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.Persistence.EntityFramework.SqlServer", "src\persistence\Elsa.Persistence.EntityFramework\Elsa.Persistence.EntityFramework.SqlServer\Elsa.Persistence.EntityFramework.SqlServer.csproj", "{F97339EF-424F-46F1-AD8D-B36B8C2F716E}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.Samples.Faulting", "src\samples\worker\Elsa.Samples.Faulting\Elsa.Samples.Faulting.csproj", "{76BF833E-3CAE-4402-99F1-B3BFD90622E4}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
|
@ -514,6 +516,10 @@ Global
|
|||
{F97339EF-424F-46F1-AD8D-B36B8C2F716E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{F97339EF-424F-46F1-AD8D-B36B8C2F716E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{F97339EF-424F-46F1-AD8D-B36B8C2F716E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{76BF833E-3CAE-4402-99F1-B3BFD90622E4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{76BF833E-3CAE-4402-99F1-B3BFD90622E4}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{76BF833E-3CAE-4402-99F1-B3BFD90622E4}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{76BF833E-3CAE-4402-99F1-B3BFD90622E4}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
|
@ -615,6 +621,7 @@ Global
|
|||
{7240B7EE-53D7-4C94-9A5C-80D2D6C4BF0E} = {C865B0FD-E505-48F0-BFAF-0D4D7C1B5CA1}
|
||||
{8A7C2A43-BABF-4961-81D8-D16A702A2EE8} = {C865B0FD-E505-48F0-BFAF-0D4D7C1B5CA1}
|
||||
{F97339EF-424F-46F1-AD8D-B36B8C2F716E} = {C865B0FD-E505-48F0-BFAF-0D4D7C1B5CA1}
|
||||
{76BF833E-3CAE-4402-99F1-B3BFD90622E4} = {E42743A0-FBDD-4150-9D53-6000496D9B87}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {8B0975FD-7050-48B0-88C5-48C33378E158}
|
||||
|
|
|
|||
|
|
@ -5,10 +5,11 @@ namespace Elsa.ActivityResults
|
|||
{
|
||||
public class FaultResult : ActivityExecutionResult
|
||||
{
|
||||
public FaultResult(LocalizedString message) => Message = message;
|
||||
public LocalizedString Message { get; }
|
||||
public FaultResult(string message) => Message = message;
|
||||
public string Message { get; set; }
|
||||
public string? StackTrace { get; set; }
|
||||
|
||||
protected override void Execute(ActivityExecutionContext activityExecutionContext) =>
|
||||
activityExecutionContext.WorkflowExecutionContext.Fault(activityExecutionContext.ActivityBlueprint.Id, Message);
|
||||
activityExecutionContext.WorkflowExecutionContext.Fault(activityExecutionContext.ActivityBlueprint.Id, Message, StackTrace);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,8 +1,4 @@
|
|||
namespace Elsa.Models
|
||||
{
|
||||
public class WorkflowFault
|
||||
{
|
||||
public string? FaultedActivityId { get; set; }
|
||||
public string? Message { get; set; }
|
||||
}
|
||||
public record WorkflowFault(string? FaultedActivityId, string? Message, string? StackTrace);
|
||||
}
|
||||
|
|
@ -47,7 +47,7 @@ namespace Elsa.Services
|
|||
protected ScheduleActivitiesResult Schedule(IEnumerable<ScheduledActivity> activities) => new(activities);
|
||||
protected CombinedResult Combine(IEnumerable<IActivityExecutionResult> results) => new(results);
|
||||
protected CombinedResult Combine(params IActivityExecutionResult[] results) => new(results);
|
||||
protected FaultResult Fault(LocalizedString message) => new(message);
|
||||
protected FaultResult Fault(string message) => new(message);
|
||||
|
||||
protected T? GetState<T>([CallerMemberName] string name = null!) => Data.GetState<T>(name);
|
||||
protected T GetState<T>(Func<T> defaultValue, [CallerMemberName] string name = null!) => Data.GetState(name, defaultValue);
|
||||
|
|
|
|||
|
|
@ -1,10 +0,0 @@
|
|||
using Microsoft.Extensions.Localization;
|
||||
|
||||
namespace Elsa.Services.Models
|
||||
{
|
||||
public interface IWorkflowFault
|
||||
{
|
||||
string? FaultedActivityId { get; }
|
||||
LocalizedString? Message { get; }
|
||||
}
|
||||
}
|
||||
|
|
@ -1,23 +0,0 @@
|
|||
namespace Elsa.Services.Models
|
||||
{
|
||||
public class ProcessFault
|
||||
{
|
||||
public ProcessFault(IActivity faultedActivity, string message)
|
||||
{
|
||||
FaultedActivity = faultedActivity;
|
||||
Message = message;
|
||||
}
|
||||
|
||||
public IActivity FaultedActivity { get; }
|
||||
public string Message { get; }
|
||||
|
||||
public Elsa.Models.WorkflowFault ToInstance()
|
||||
{
|
||||
return new()
|
||||
{
|
||||
FaultedActivityId = FaultedActivity?.Id,
|
||||
Message = Message
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -8,6 +8,7 @@ using Elsa.Models;
|
|||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Localization;
|
||||
using Newtonsoft.Json;
|
||||
using NodaTime;
|
||||
|
||||
namespace Elsa.Services.Models
|
||||
{
|
||||
|
|
@ -34,7 +35,6 @@ namespace Elsa.Services.Models
|
|||
public JsonSerializer Serializer { get; }
|
||||
public object? Input { get; }
|
||||
public bool HasScheduledActivities => WorkflowInstance.ScheduledActivities.Any();
|
||||
public IWorkflowFault? WorkflowFault { get; private set; }
|
||||
public bool IsFirstPass { get; private set; }
|
||||
public bool ContextHasChanged { get; set; }
|
||||
|
||||
|
|
@ -114,10 +114,12 @@ namespace Elsa.Services.Models
|
|||
public void Resume() => WorkflowInstance.WorkflowStatus = WorkflowStatus.Running;
|
||||
public void Suspend() => WorkflowInstance.WorkflowStatus = WorkflowStatus.Suspended;
|
||||
|
||||
public void Fault(string? activityId, LocalizedString? message)
|
||||
public void Fault(string? activityId, string? message, string? stackTrace)
|
||||
{
|
||||
var clock = ServiceScope.ServiceProvider.GetRequiredService<IClock>();
|
||||
WorkflowInstance.WorkflowStatus = WorkflowStatus.Faulted;
|
||||
WorkflowFault = new WorkflowFault(activityId, message);
|
||||
WorkflowInstance.FaultedAt = clock.GetCurrentInstant();
|
||||
WorkflowInstance.Fault = new WorkflowFault(activityId, message, stackTrace);
|
||||
}
|
||||
|
||||
public void Complete() => WorkflowInstance.WorkflowStatus = WorkflowStatus.Finished;
|
||||
|
|
|
|||
|
|
@ -1,16 +0,0 @@
|
|||
using Microsoft.Extensions.Localization;
|
||||
|
||||
namespace Elsa.Services.Models
|
||||
{
|
||||
public class WorkflowFault : IWorkflowFault
|
||||
{
|
||||
public WorkflowFault(string? activityId = default, LocalizedString? message = default)
|
||||
{
|
||||
FaultedActivityId = activityId;
|
||||
Message = message;
|
||||
}
|
||||
|
||||
public string? FaultedActivityId { get; }
|
||||
public LocalizedString? Message { get; }
|
||||
}
|
||||
}
|
||||
|
|
@ -269,7 +269,7 @@ namespace Elsa.Services
|
|||
catch (Exception e)
|
||||
{
|
||||
_logger.LogError(e, e.Message);
|
||||
workflowExecutionContext.Fault(null, new LocalizedString(e.Message, e.Message));
|
||||
workflowExecutionContext.Fault(null, e.Message, e.StackTrace);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -286,7 +286,12 @@ namespace Elsa.Services
|
|||
var activityExecutionContext = new ActivityExecutionContext(scope, workflowExecutionContext, activityBlueprint, scheduledActivity.Input, cancellationToken);
|
||||
var activity = await activityExecutionContext.ActivateActivityAsync(cancellationToken);
|
||||
await _mediator.Publish(new ActivityExecuting(activityExecutionContext), cancellationToken);
|
||||
var result = await activityOperation(activityExecutionContext, activity);
|
||||
|
||||
var result = await TryExecuteActivityAsync(activityOperation, activityExecutionContext, activity);
|
||||
|
||||
if(result == null)
|
||||
return;
|
||||
|
||||
await _mediator.Publish(new ActivityExecuted(activityExecutionContext), cancellationToken);
|
||||
await result.ExecuteAsync(activityExecutionContext, cancellationToken);
|
||||
workflowExecutionContext.WorkflowInstance.Output = activityExecutionContext.Output;
|
||||
|
|
@ -305,5 +310,20 @@ namespace Elsa.Services
|
|||
if (workflowExecutionContext.Status == WorkflowStatus.Running)
|
||||
workflowExecutionContext.Complete();
|
||||
}
|
||||
|
||||
private async ValueTask<IActivityExecutionResult?> TryExecuteActivityAsync(ActivityOperation activityOperation, ActivityExecutionContext activityExecutionContext, RuntimeActivityInstance activity)
|
||||
{
|
||||
try
|
||||
{
|
||||
return await activityOperation(activityExecutionContext, activity);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.LogError(e, e.Message);
|
||||
activityExecutionContext.WorkflowExecutionContext.Fault(activity.Id, e.Message, e.StackTrace);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Elsa.DistributedLock;
|
||||
|
|
@ -6,6 +7,8 @@ using Elsa.Models;
|
|||
using Elsa.Persistence;
|
||||
using Elsa.Persistence.Specifications;
|
||||
using Elsa.Services;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Open.Linq.AsyncExtensions;
|
||||
|
||||
namespace Elsa.StartupTasks
|
||||
{
|
||||
|
|
@ -18,15 +21,18 @@ namespace Elsa.StartupTasks
|
|||
private readonly IWorkflowInstanceStore _workflowInstanceStore;
|
||||
private readonly IWorkflowRunner _workflowScheduler;
|
||||
private readonly IDistributedLockProvider _distributedLockProvider;
|
||||
private readonly ILogger<ResumeRunningWorkflowsTask> _logger;
|
||||
|
||||
public ResumeRunningWorkflowsTask(
|
||||
IWorkflowInstanceStore workflowInstanceStore,
|
||||
IWorkflowRunner workflowScheduler,
|
||||
IDistributedLockProvider distributedLockProvider)
|
||||
IDistributedLockProvider distributedLockProvider,
|
||||
ILogger<ResumeRunningWorkflowsTask> logger)
|
||||
{
|
||||
_workflowInstanceStore = workflowInstanceStore;
|
||||
_workflowScheduler = workflowScheduler;
|
||||
_distributedLockProvider = distributedLockProvider;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public async Task ExecuteAsync(CancellationToken cancellationToken = default)
|
||||
|
|
@ -38,12 +44,17 @@ namespace Elsa.StartupTasks
|
|||
|
||||
try
|
||||
{
|
||||
var instances = await _workflowInstanceStore.FindManyAsync(new WorkflowStatusSpecification(WorkflowStatus.Running), cancellationToken: cancellationToken);
|
||||
var instances = await _workflowInstanceStore.FindManyAsync(new WorkflowStatusSpecification(WorkflowStatus.Running), cancellationToken: cancellationToken).ToList();
|
||||
|
||||
_logger.LogInformation("Found {WorkflowInstanceCount} workflows with status 'Running'. Resuming each one of them.", instances.Count);
|
||||
|
||||
foreach (var instance in instances)
|
||||
{
|
||||
_logger.LogInformation("Resuming {WorkflowInstanceId}", instance.Id);
|
||||
await _workflowScheduler.RunWorkflowAsync(
|
||||
instance,
|
||||
cancellationToken: cancellationToken);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
|
|
|||
|
|
@ -129,7 +129,7 @@ namespace Elsa.Triggers
|
|||
var workflowBlueprints = await _workflowRegistry.GetWorkflowsAsync(cancellationToken).ToListAsync(cancellationToken);
|
||||
var descriptors = new List<TriggerDescriptor>();
|
||||
|
||||
foreach (var workflowBlueprint in workflowBlueprints)
|
||||
foreach (var workflowBlueprint in workflowBlueprints.Where(x => x.IsEnabled))
|
||||
{
|
||||
var blueprintDescriptors = await BuildDescriptorsForAsync(workflowBlueprint, null, cancellationToken);
|
||||
descriptors.AddRange(blueprintDescriptors);
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@
|
|||
<ProjectReference Include="..\..\..\activities\Elsa.Activities.AzureServiceBus\Elsa.Activities.AzureServiceBus.csproj" />
|
||||
<ProjectReference Include="..\..\..\activities\Elsa.Activities.Timers.Quartz\Elsa.Activities.Timers.Quartz.csproj" />
|
||||
<ProjectReference Include="..\..\..\core\Elsa\Elsa.csproj" />
|
||||
<ProjectReference Include="..\..\..\core\Elsa\Elsa.csproj" />
|
||||
<ProjectReference Include="..\..\..\persistence\Elsa.Persistence.EntityFramework\Elsa.Persistence.EntityFramework.Sqlite\Elsa.Persistence.EntityFramework.Sqlite.csproj" />
|
||||
<ProjectReference Include="..\..\..\persistence\Elsa.Persistence.YesSql\Elsa.Persistence.YesSql.csproj" />
|
||||
</ItemGroup>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,17 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk.Worker">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
<IsPackable>false</IsPackable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="5.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\activities\Elsa.Activities.Timers.Quartz\Elsa.Activities.Timers.Quartz.csproj" />
|
||||
<ProjectReference Include="..\..\..\core\Elsa\Elsa.csproj" />
|
||||
<ProjectReference Include="..\..\..\persistence\Elsa.Persistence.YesSql\Elsa.Persistence.YesSql.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
27
src/samples/worker/Elsa.Samples.Faulting/Program.cs
Normal file
27
src/samples/worker/Elsa.Samples.Faulting/Program.cs
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
using Elsa.Persistence.YesSql.Extensions;
|
||||
using Elsa.Samples.Faulting.Workflows;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
|
||||
namespace Elsa.Samples.Faulting
|
||||
{
|
||||
public class Program
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
CreateHostBuilder(args).Build().Run();
|
||||
}
|
||||
|
||||
public static IHostBuilder CreateHostBuilder(string[] args) =>
|
||||
Host.CreateDefaultBuilder(args)
|
||||
.ConfigureServices((_, services) =>
|
||||
{
|
||||
services
|
||||
.AddElsa(options => options
|
||||
.UseYesSqlPersistence()
|
||||
.AddConsoleActivities()
|
||||
.AddQuartzTimerActivities()
|
||||
.AddWorkflow<FaultyWorkflow>());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"profiles": {
|
||||
"Elsa.Samples.Faulting": {
|
||||
"commandName": "Project",
|
||||
"dotnetRunMessages": "true",
|
||||
"environmentVariables": {
|
||||
"DOTNET_ENVIRONMENT": "Development"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
using System;
|
||||
using Elsa.Activities.Console;
|
||||
using Elsa.Activities.Timers;
|
||||
using Elsa.Builders;
|
||||
using NodaTime;
|
||||
|
||||
namespace Elsa.Samples.Faulting.Workflows
|
||||
{
|
||||
public class FaultyWorkflow : IWorkflow
|
||||
{
|
||||
public void Build(IWorkflowBuilder workflow)
|
||||
{
|
||||
workflow
|
||||
.StartIn(Duration.FromSeconds(1))
|
||||
.WriteLine("Catch this!")
|
||||
.Then(() => throw new ArithmeticException("Does not compute"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft": "Warning",
|
||||
"Microsoft.Hosting.Lifetime": "Information"
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue