Only evaluate designer-critical properties.

Fixes #1163
This commit is contained in:
Sipke Schoorstra 2021-07-24 11:52:08 +02:00
parent 472358f9e7
commit e55b2fbf60
8 changed files with 53 additions and 28 deletions

View file

@ -102,8 +102,11 @@ namespace Elsa.Services.Workflows
if (!runWorkflowResult.Executed)
{
_logger.LogDebug("Workflow {WorkflowInstanceId} cannot begin from an idle state (perhaps it needs a specific input)", workflowInstance.Id);
return runWorkflowResult;
if (workflowInstance.WorkflowStatus != WorkflowStatus.Faulted)
{
_logger.LogDebug("Workflow {WorkflowInstanceId} cannot begin from an idle state (perhaps it needs a specific input)", workflowInstance.Id);
return runWorkflowResult;
}
}
break;
@ -140,7 +143,6 @@ namespace Elsa.Services.Workflows
if (statusEvent != null)
{
_logger.LogTrace("Publishing a status event of type {EventType} for workflow {WorkflowInstanceId}", statusEvent.GetType().Name, workflowInstance.Id);
await _mediator.Publish(statusEvent, cancellationToken);
}
@ -153,13 +155,23 @@ namespace Elsa.Services.Workflows
if (activity == null)
activity = _startingActivitiesProvider.GetStartActivities(workflowExecutionContext.WorkflowBlueprint).FirstOrDefault() ?? workflowExecutionContext.WorkflowBlueprint.Activities.First();
if (!await CanExecuteAsync(workflowExecutionContext, activity, false, cancellationToken))
return new RunWorkflowResult(workflowExecutionContext.WorkflowInstance, activity.Id, false);
try
{
if (!await CanExecuteAsync(workflowExecutionContext, activity, false, cancellationToken))
return new RunWorkflowResult(workflowExecutionContext.WorkflowInstance, activity.Id, false);
workflowExecutionContext.Begin();
workflowExecutionContext.ScheduleActivity(activity.Id);
await RunAsync(workflowExecutionContext, Execute, cancellationToken);
return new RunWorkflowResult(workflowExecutionContext.WorkflowInstance, activity.Id, true);
}
catch (Exception e)
{
_logger.LogWarning(e, "Failed to run workflow {WorkflowInstanceId}", workflowExecutionContext.WorkflowInstance.Id);
workflowExecutionContext.Fault(e, null, null, false);
}
workflowExecutionContext.Begin();
workflowExecutionContext.ScheduleActivity(activity.Id);
await RunAsync(workflowExecutionContext, Execute, cancellationToken);
return new RunWorkflowResult(workflowExecutionContext.WorkflowInstance, activity.Id, true);
return new RunWorkflowResult(workflowExecutionContext.WorkflowInstance, activity.Id, false);
}
private async Task RunWorkflowAsync(WorkflowExecutionContext workflowExecutionContext, CancellationToken cancellationToken)

View file

@ -70,10 +70,6 @@ namespace Elsa.Samples.Server.Host
.ConfigureWorkflowChannels(options => elsaSection.GetSection("WorkflowChannels").Bind(options))
);
// Hangfire.
services.AddHangfire(configuration => configuration.UseSqlServerStorage(Configuration.GetConnectionString("SqlServer")));
services.AddHangfireServer((sp, options)=> options.ConfigureForElsaDispatchers(sp));
// Elsa API endpoints.
services
.AddElsaApiEndpoints()

View file

@ -24,7 +24,7 @@
"Framework": "EntityFrameworkCore",
"ConnectionStringIdentifier": "Sqlite"
},
"DispatcherHangfire": true,
"DispatcherHangfire": false,
"Console": true,
"Http": true,
"Email": true,

View file

@ -5,6 +5,7 @@ using Microsoft.AspNetCore.Mvc;
using Swashbuckle.AspNetCore.Annotations;
using System.Threading;
using System.Threading.Tasks;
using Elsa.Models;
namespace Elsa.Server.Api.Endpoints.Workflows
{
@ -41,7 +42,7 @@ namespace Elsa.Server.Api.Endpoints.Workflows
if (startableWorkflow == null)
return NotFound();
var result = await _workflowLaunchpad.DispatchStartableWorkflowAsync(startableWorkflow, request.Input, cancellationToken);
var result = await _workflowLaunchpad.DispatchStartableWorkflowAsync(startableWorkflow, new WorkflowInput(request.Input), cancellationToken);
return Ok(new DispatchWorkflowDefinitionResponseModel(result.WorkflowInstanceId, result.ActivityId));
}
}

View file

@ -5,6 +5,7 @@ using Microsoft.AspNetCore.Mvc;
using Swashbuckle.AspNetCore.Annotations;
using System.Threading;
using System.Threading.Tasks;
using Elsa.Models;
namespace Elsa.Server.Api.Endpoints.Workflows
{
@ -41,7 +42,7 @@ namespace Elsa.Server.Api.Endpoints.Workflows
if (startableWorkflow == null)
return NotFound();
var result = await _workflowLaunchpad.ExecuteStartableWorkflowAsync(startableWorkflow, request.Input, cancellationToken);
var result = await _workflowLaunchpad.ExecuteStartableWorkflowAsync(startableWorkflow, new WorkflowInput(request.Input), cancellationToken);
if (Response.HasStarted)
return new EmptyResult();

View file

@ -6,20 +6,20 @@ using Elsa.Services.Models;
namespace Elsa.Server.Api.Endpoints.Workflows
{
public record ExecuteWorkflowDefinitionRequestModel(string? ActivityId, string? CorrelationId, string? ContextId, WorkflowInput? Input);
public record ExecuteWorkflowDefinitionRequestModel(string? ActivityId, string? CorrelationId, string? ContextId, object? Input);
public record ExecuteWorkflowDefinitionResponseModel(bool Executed, string? ActivityId, WorkflowInstance? WorkflowInstance);
public record DispatchWorkflowDefinitionRequestModel(string? ActivityId, string? CorrelationId, string? ContextId, WorkflowInput? Input);
public record DispatchWorkflowDefinitionRequestModel(string? ActivityId, string? CorrelationId, string? ContextId, object? Input);
public record DispatchWorkflowDefinitionResponseModel(string WorkflowInstanceId, string? ActivityId);
public record TriggeredWorkflowModel(string WorkflowInstanceId, string? ActivityId);
public record DispatchTriggerWorkflowsRequestModel(string ActivityType, IBookmark? Bookmark, IBookmark? Trigger, string? CorrelationId, string? WorkflowInstanceId, string? ContextId, WorkflowInput? Input);
public record DispatchTriggerWorkflowsRequestModel(string ActivityType, IBookmark? Bookmark, IBookmark? Trigger, string? CorrelationId, string? WorkflowInstanceId, string? ContextId, object? Input);
public record DispatchTriggerWorkflowsResponseModel(ICollection<CollectedWorkflow> PendingWorkflows);
public record TriggerWorkflowsRequestModel(string ActivityType, IBookmark? Bookmark, string? CorrelationId, string? WorkflowInstanceId, string? ContextId, WorkflowInput? Input, bool Dispatch);
public record TriggerWorkflowsRequestModel(string ActivityType, IBookmark? Bookmark, string? CorrelationId, string? WorkflowInstanceId, string? ContextId, object? Input, bool Dispatch);
public record TriggerWorkflowsResponseModel(ICollection<TriggeredWorkflowModel> TriggeredWorkflows);
}

View file

@ -2,6 +2,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Elsa.Models;
using Elsa.Server.Api.ActionFilters;
using Elsa.Services;
using Elsa.Services.Models;
@ -44,12 +45,12 @@ namespace Elsa.Server.Api.Endpoints.Workflows
if (request.Dispatch)
{
var result = await _workflowLaunchpad.CollectAndDispatchWorkflowsAsync(context, request.Input, cancellationToken).ToList();
var result = await _workflowLaunchpad.CollectAndDispatchWorkflowsAsync(context, new WorkflowInput(request.Input), cancellationToken).ToList();
triggeredWorkflows = result.Select(x => new TriggeredWorkflowModel(x.WorkflowInstanceId, x.ActivityId)).ToList();
}
else
{
var result = await _workflowLaunchpad.CollectAndExecuteWorkflowsAsync(context, request.Input, cancellationToken).ToList();
var result = await _workflowLaunchpad.CollectAndExecuteWorkflowsAsync(context, new WorkflowInput(request.Input), cancellationToken).ToList();
triggeredWorkflows = result.Select(x => new TriggeredWorkflowModel(x.WorkflowInstanceId, x.ActivityId)).ToList();
}

View file

@ -1,7 +1,9 @@
using System.Linq;
using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using AutoMapper;
using Elsa.Exceptions;
using Elsa.Metadata;
using Elsa.Models;
using Elsa.Server.Api.Endpoints.WorkflowRegistry;
@ -68,10 +70,22 @@ namespace Elsa.Server.Api.Services
return (inputProperties, outputProperties);
}
private async Task<object?> GetPropertyValueAsync(IWorkflowBlueprint workflowBlueprint, IActivityBlueprintWrapper activityBlueprintWrapper, ActivityInputDescriptor propertyDescriptor, CancellationToken cancellationToken) =>
// Ony evaluate designer-critical properties, as they are necessary for proper designer display such as dynamic outcomes. These evaluations must not fail.
propertyDescriptor.IsDesignerCritical
? await activityBlueprintWrapper.EvaluatePropertyValueAsync(propertyDescriptor.Name, cancellationToken)
: workflowBlueprint.GetActivityPropertyRawValue(activityBlueprintWrapper.ActivityBlueprint.Id, propertyDescriptor.Name);
private static async Task<object?> GetPropertyValueAsync(IWorkflowBlueprint workflowBlueprint, IActivityBlueprintWrapper activityBlueprintWrapper, ActivityInputDescriptor propertyDescriptor, CancellationToken cancellationToken)
{
if (propertyDescriptor.IsDesignerCritical)
{
try
{
return await activityBlueprintWrapper.EvaluatePropertyValueAsync(propertyDescriptor.Name, cancellationToken);
}
catch (Exception e)
{
Console.WriteLine(e);
throw new WorkflowException("Failed to evaluate a designer-critical property value. Please make sure that the value does not rely on external context.", e);
}
}
return workflowBlueprint.GetActivityPropertyRawValue(activityBlueprintWrapper.ActivityBlueprint.Id, propertyDescriptor.Name);
}
}
}