Skip to content

Commit

Permalink
Merge pull request #6392 from elsa-workflows/enh/bulk-query-cancel
Browse files Browse the repository at this point in the history
Implement bulk cancellation using alterations and filters
  • Loading branch information
sfmskywalker authored Feb 10, 2025
2 parents 92626d4 + bec0e55 commit 6682b7f
Show file tree
Hide file tree
Showing 40 changed files with 626 additions and 23 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using Elsa.Api.Client.Resources.ActivityDescriptorOptions.Contracts;
using Elsa.Api.Client.Resources.ActivityDescriptors.Contracts;
using Elsa.Api.Client.Resources.ActivityExecutions.Contracts;
using Elsa.Api.Client.Resources.Alterations.Contracts;
using Elsa.Api.Client.Resources.Features.Contracts;
using Elsa.Api.Client.Resources.Identity.Contracts;
using Elsa.Api.Client.Resources.IncidentStrategies.Contracts;
Expand Down Expand Up @@ -68,6 +69,7 @@ public static IServiceCollection AddDefaultApiClients(this IServiceCollection se
services.AddApi<IJavaScriptApi>(builderOptions);
services.AddApi<IExpressionDescriptorsApi>(builderOptions);
services.AddApi<IWorkflowContextProviderDescriptorsApi>(builderOptions);
services.AddApi<IAlterationsApi>(builderOptions);
});
}

Expand Down
5 changes: 4 additions & 1 deletion src/clients/Elsa.Api.Client/Helpers/RefitSettingsHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@ public static class RefitSettingsHelper
/// </summary>
public static RefitSettings CreateRefitSettings(IServiceProvider serviceProvider, Action<IServiceProvider, JsonSerializerOptions>? configureJsonSerializerOptions = null)
{
var settings = new RefitSettings { ContentSerializer = new SystemTextJsonContentSerializer(CreateJsonSerializerOptions(serviceProvider, configureJsonSerializerOptions)) };
var settings = new RefitSettings
{
ContentSerializer = new SystemTextJsonContentSerializer(CreateJsonSerializerOptions(serviceProvider, configureJsonSerializerOptions))
};

return settings;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
using Elsa.Api.Client.Resources.Alterations.Models;
using Elsa.Api.Client.Resources.Alterations.Requests;
using Elsa.Api.Client.Resources.Alterations.Responses;
using Refit;

namespace Elsa.Api.Client.Resources.Alterations.Contracts;

/// <summary>
/// Represents a client for the alterations API. Requires the Elsa.Alterations feature.
/// </summary>
public interface IAlterationsApi
{
/// <summary>
/// Returns an alteration plan and its associated jobs.
/// </summary>
/// <param name="id">The ID of the alteration plan to return.</param>
/// <param name="cancellationToken">The cancellation token.</param>
[Get("/alterations/{id}")]
Task<GetAlterationPlanResponse> GetAsync(string id, CancellationToken cancellationToken = default);

/// <summary>
/// Determines which workflow instances a "Submit" request would target without actually running an alteration
/// </summary>
/// <param name="request">The requested workflow filter to dry run</param>
/// <param name="cancellationToken">The cancellation token.</param>
[Post("/alterations/dry-run")]
Task<DryRunResponse> DryRun(AlterationWorkflowInstanceFilter request, CancellationToken cancellationToken = default);

/// <summary>
/// Submits an alteration plan and a filter for workflows instances to be executed against
/// </summary>
/// <param name="request">The alterations and filter to submit</param>
/// <param name="cancellationToken">The cancellation token.</param>
[Post("/alterations/submit")]
Task<SubmitResponse> Submit(AlterationPlanParams request, CancellationToken cancellationToken = default);

/// <summary>
/// Runs an alteration plan and a list of workflow Instance Ids to be executed against
/// </summary>
/// <param name="request">The alterations and workflowInstanceIds to execute</param>
/// <param name="cancellationToken">The cancellation token.</param>
[Post("/alterations/run")]
Task<RunResponse> Run(RunRequest request, CancellationToken cancellationToken = default);

/// <summary>
/// Retries the specified workflow instances.
/// </summary>
/// <param name="request">The request containing the selection of workflow instances to retry.</param>
/// <param name="cancellationToken">The cancellation token.</param>
[Post("/alterations/workflows/retry")]
Task<BulkRetryResponse> BulkRetryAsync(BulkRetryRequest request, CancellationToken cancellationToken);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
namespace Elsa.Api.Client.Resources.Alterations.Enums;

/// <summary>
/// Represents the status of an activity.
/// </summary>
public enum ActivityStatus
{
/// <summary>
/// The activity is in the Pending state.
/// </summary>
Pending,

/// <summary>
/// The activity is in the Running state. Note that event if an activity is running, it may not be executing.
/// </summary>
Running,

/// <summary>
/// The activity is in the Completed state.
/// </summary>
Completed,

/// <summary>
/// The activity is in the Canceled state.
/// </summary>
Canceled,

/// <summary>
/// The activity is in the Faulted state.
/// </summary>
Faulted
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
namespace Elsa.Api.Client.Resources.Alterations.Enums;

/// <summary>
/// The status of an alteration plan for a workflow instance.
/// </summary>
public enum AlterationJobStatus
{
/// <summary>
/// The plan is pending execution.
/// </summary>
Pending,

/// <summary>
/// The plan is currently being executed.
/// </summary>
Running,

/// <summary>
/// The plan has been completed.
/// </summary>
Completed,

/// <summary>
/// The job has failed.
/// </summary>
Failed
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
namespace Elsa.Api.Client.Resources.Alterations.Enums;

/// <summary>
/// The status of an alteration plan.
/// </summary>
public enum AlterationPlanStatus
{
/// <summary>
/// The plan is pending execution.
/// </summary>
Pending,

/// <summary>
/// The plan is currently generating jobs.
/// </summary>
Generating,

/// <summary>
/// The plan is currently dispatching jobs.
/// </summary>
Dispatching,

/// <summary>
/// The plan is currently being executed.
/// </summary>
Running,

/// <summary>
/// The plan has been completed.
/// </summary>
Completed,

/// <summary>
/// The plan has failed.
/// </summary>
Failed
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using Elsa.Api.Client.Resources.Alterations.Enums;

namespace Elsa.Api.Client.Resources.Alterations.Models;

/// <summary>
/// A filter for activities within a workflow instance
/// </summary>
public class ActivityFilter
{
/// <summary>
/// The ID of the activity.
/// </summary>
public string? ActivityId { get; set; }

/// <summary>
/// The ID of the activity instance.
/// </summary>
public string? ActivityInstanceId { get; set; }

/// <summary>
/// The node ID of the activity.
/// </summary>
public string? NodeId { get; set; }

/// <summary>
/// The name of the activity.
/// </summary>
public string? Name { get; set; }

/// <summary>
/// The status of the activity.
/// </summary>
public ActivityStatus? Status { get; set; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
using Elsa.Api.Client.Resources.Alterations.Enums;
using Elsa.Api.Client.Shared.Models;

namespace Elsa.Api.Client.Resources.Alterations.Models;

/// <summary>
/// Represents the execution of the plan for an individual workflow instance.
/// </summary>
public class AlterationJob : Entity
{
/// <summary>
/// The ID of the plan that this job belongs to.
/// </summary>
public string PlanId { get; set; } = default!;

/// <summary>
/// The ID of the workflow instance that this job applies to.
/// </summary>
public string WorkflowInstanceId { get; set; } = default!;

/// <summary>
/// The status of the job.
/// </summary>
public AlterationJobStatus Status { get; set; }

/// <summary>
/// The serialized log of the job.
/// </summary>
public ICollection<AlterationLogEntry>? Log { get; set; } = new List<AlterationLogEntry>();

/// <summary>
/// The date and time at which the job was created.
/// </summary>
public DateTimeOffset CreatedAt { get; set; }

/// <summary>
/// The date and time at which the job was started.
/// </summary>
public DateTimeOffset? StartedAt { get; set; }

/// <summary>
/// The date and time at which the job was completed.
/// </summary>
public DateTimeOffset? CompletedAt { get; set; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
namespace Elsa.Api.Client.Resources.Alterations.Models;

/// <summary>
/// Represents a log of alterations.
/// </summary>
public class AlterationLog
{

/// <summary>
/// The log entries.
/// </summary>
public ICollection<AlterationLogEntry> LogEntries { get; set; } = new List<AlterationLogEntry>();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using Microsoft.Extensions.Logging;

namespace Elsa.Api.Client.Resources.Alterations.Models;

/// <summary>
/// An individual log entry about an alteration
/// </summary>
/// <param name="Message"></param>
/// <param name="LogLevel"></param>
/// <param name="Timestamp"></param>
/// <param name="EventName"></param>
public record AlterationLogEntry(string Message, LogLevel LogLevel, DateTimeOffset Timestamp, string? EventName = null);
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
using System.Text.Json.Nodes;
using Elsa.Api.Client.Resources.Alterations.Enums;
using Elsa.Api.Client.Shared.Models;

namespace Elsa.Api.Client.Resources.Alterations.Models;

/// <summary>
/// A plan that contains a list of alterations to be applied to a set of workflow instances.
/// </summary>
public class AlterationPlan : Entity
{
/// <summary>
/// The alterations to be applied.
/// </summary>
public ICollection<JsonObject> Alterations { get; set; } = new List<JsonObject>();

/// <summary>
/// The IDs of the workflow instances that this plan applies to.
/// </summary>
public AlterationWorkflowInstanceFilter WorkflowInstanceFilter { get; set; } = new();

/// <summary>
/// The status of the plan.
/// </summary>
public AlterationPlanStatus Status { get; set; }

/// <summary>
/// The date and time at which the plan was created.
/// </summary>
public DateTimeOffset CreatedAt { get; set; }

/// <summary>
/// The date and time at which the plan was started.
/// </summary>
public DateTimeOffset? StartedAt { get; set; }

/// <summary>
/// The date and time at which the plan was completed.
/// </summary>
public DateTimeOffset? CompletedAt { get; set; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using System.Text.Json.Nodes;

namespace Elsa.Api.Client.Resources.Alterations.Models;

/// <summary>
/// Represents the execution of an alteration plan against a set of workflow instances defined by the given filter
/// </summary>
public class AlterationPlanParams
{
/// <summary>
/// The unique identifier for the alteration plan. If not specified, a new ID will be generated.
/// </summary>
public string? Id { get; set; }

/// <summary>
/// The alterations to be applied.
/// </summary>
public ICollection<JsonObject> Alterations { get; set; } = new List<JsonObject>();

/// <summary>
/// The IDs of the workflow instances that this plan applies to.
/// </summary>
public AlterationWorkflowInstanceFilter Filter { get; set; } = new();
}
Loading

0 comments on commit 6682b7f

Please sign in to comment.