Refactor workflow instance listing and enum parsing

Refactor the endpoint for listing workflow instances to use a more robust enum parsing method and improve validation. Update models to accept string collections for statuses and sub-statuses, which enables validating and parsing these enums directly within the endpoint.
This commit is contained in:
Sipke Schoorstra 2024-03-13 18:59:05 +01:00
parent cad90e4e4e
commit 15518ba6db
4 changed files with 31 additions and 13 deletions

View file

@ -1,3 +1,4 @@
using Elsa.Extensions;
using Elsa.Samples.AspNet.BatchProcessing.Activities;
using Elsa.Samples.AspNet.BatchProcessing.Models;
using Elsa.Workflows;
@ -14,7 +15,7 @@ public class OrderBatchProcessor : WorkflowBase
/// <inheritdoc />
protected override void Build(IWorkflowBuilder builder)
{
var orders = builder.WithVariable<IAsyncEnumerable<ICollection<Order>>>();
var orders = builder.WithVariable<IAsyncEnumerable<ICollection<Order>>>().WithMemoryStorage();
builder.Root = new Sequence
{
Activities =

View file

@ -23,8 +23,12 @@ internal class List(IWorkflowInstanceStore store) : ElsaEndpoint<Request, Respon
public override async Task HandleAsync(Request request, CancellationToken cancellationToken)
{
var pageArgs = PageArgs.FromPage(request.Page, request.PageSize);
var workflowStatuses = request.Statuses?.Any() == true ? ParseEnumStrings<WorkflowStatus>(request.Statuses).ToList() : null;
var workflowSubStatuses = request.SubStatuses?.Any() == true ? ParseEnumStrings<WorkflowSubStatus>(request.SubStatuses).ToList() : null;
if (!await ValidateInputAsync(request, cancellationToken))
ValidateInput(request);
if (ValidationFailed)
{
await SendErrorsAsync(StatusCodes.Status400BadRequest, cancellationToken);
return;
@ -39,8 +43,8 @@ internal class List(IWorkflowInstanceStore store) : ElsaEndpoint<Request, Respon
CorrelationId = request.CorrelationId,
WorkflowStatus = request.Status,
WorkflowSubStatus = request.SubStatus,
WorkflowStatuses = request.Statuses?.Any() == true ? request.Statuses : null,
WorkflowSubStatuses = request.SubStatuses?.Any() == true ? request.SubStatuses : null,
WorkflowStatuses = workflowStatuses,
WorkflowSubStatuses = workflowSubStatuses,
HasIncidents = request.HasIncidents,
TimestampFilters = request.TimestampFilters?.Any() == true ? request.TimestampFilters : null,
};
@ -50,7 +54,21 @@ internal class List(IWorkflowInstanceStore store) : ElsaEndpoint<Request, Respon
await SendOkAsync(response, cancellationToken);
}
private async Task<bool> ValidateInputAsync(Request request, CancellationToken cancellationToken)
private IEnumerable<TEnum> ParseEnumStrings<TEnum>(IEnumerable<string> strings) where TEnum : struct
{
foreach (string s in strings)
{
if (Enum.TryParse<TEnum>(s, true, out var result))
yield return result;
else
{
AddError($"Invalid enum value '{s}'.");
yield break;
}
}
}
private bool ValidateInput(Request request)
{
if (request.Page is < 0)
{

View file

@ -16,9 +16,9 @@ public class Request
public int? Version { get; set; }
public bool? HasIncidents { get; set; }
public WorkflowStatus? Status { get; set; }
public ICollection<WorkflowStatus>? Statuses { get; set; }
public ICollection<string>? Statuses { get; set; }
public WorkflowSubStatus? SubStatus { get; set; }
public ICollection<WorkflowSubStatus>? SubStatuses { get; set; }
public ICollection<string>? SubStatuses { get; set; }
public OrderByWorkflowInstance? OrderBy { get; set; }
public OrderDirection? OrderDirection { get; set; }
public ICollection<TimestampFilter>? TimestampFilters { get; set; }

View file

@ -43,8 +43,10 @@ public class ParallelForEach<T> : Activity
var items = context.GetItemSource<T>(Items);
var tags = new List<Guid>();
var currentIndex = 0;
// Iterate over the items.
context.SetProperty(ScheduledTagsProperty, tags);
context.SetProperty(CompletedTagsProperty, new List<Guid>());
await foreach (var item in items)
{
// For each item, declare a new variable for the work to be scheduled.
@ -62,10 +64,7 @@ public class ParallelForEach<T> : Activity
tags.Add(tag);
await context.ScheduleActivityAsync(Body, OnChildCompleted, tag, variables);
}
context.SetProperty(ScheduledTagsProperty, tags);
context.SetProperty(CompletedTagsProperty, new List<Guid>());
// If there were no items, we're done.
if (tags.Count == 0)
await context.CompleteActivityAsync();