diff --git a/src/modules/agents/Elsa.Agents.Activities/ActivityProviders/AgentActivityProvider.cs b/src/modules/agents/Elsa.Agents.Activities/ActivityProviders/AgentActivityProvider.cs index 4d4d8972..b765c09f 100644 --- a/src/modules/agents/Elsa.Agents.Activities/ActivityProviders/AgentActivityProvider.cs +++ b/src/modules/agents/Elsa.Agents.Activities/ActivityProviders/AgentActivityProvider.cs @@ -52,11 +52,12 @@ private async Task CreateAgentActivityDescriptor(AgentConfig activityDescriptor.Constructor = context => { - var activity = context.CreateActivity(); + var result = context.CreateActivity(); + var activity = result.Activity; activity.Type = activityTypeName; activity.AgentName = agentConfig.Name; activity.RunAsynchronously = true; - return activity; + return result; }; activityDescriptor.Inputs.Clear(); diff --git a/src/modules/cms/Elsa.OrchardCore/ActivityProviders/OrchardContentItemsEventActivityProvider.cs b/src/modules/cms/Elsa.OrchardCore/ActivityProviders/OrchardContentItemsEventActivityProvider.cs index 43f77d3e..35b1c7f6 100644 --- a/src/modules/cms/Elsa.OrchardCore/ActivityProviders/OrchardContentItemsEventActivityProvider.cs +++ b/src/modules/cms/Elsa.OrchardCore/ActivityProviders/OrchardContentItemsEventActivityProvider.cs @@ -50,11 +50,12 @@ private async Task CreateActivityDescriptorAsync(string cont activityDescriptor.Description = description; activityDescriptor.Constructor = context => { - var activity = context.CreateActivity(); + var result = context.CreateActivity(); + var activity = result.Activity; activity.Type = fullTypeName; activity.ContentType = contentType; activity.EventType = eventType; - return activity; + return result; }; foreach (var inputDescriptor in activityDescriptor.Inputs) diff --git a/src/modules/http/Elsa.Http.Webhooks/ActivityProviders/WebhookEventActivityProvider.cs b/src/modules/http/Elsa.Http.Webhooks/ActivityProviders/WebhookEventActivityProvider.cs index ecef19ea..76004546 100644 --- a/src/modules/http/Elsa.Http.Webhooks/ActivityProviders/WebhookEventActivityProvider.cs +++ b/src/modules/http/Elsa.Http.Webhooks/ActivityProviders/WebhookEventActivityProvider.cs @@ -41,11 +41,12 @@ private async Task CreateActivityDescriptorAsync(WebhookSour activityDescriptor.Description = eventTypeDescription; activityDescriptor.Constructor = context => { - var activity = context.CreateActivity(); + var result = context.CreateActivity(); + var activity = result.Activity; activity.Type = fullTypeName; activity.EventType = eventType.EventType; activity.PayloadType = eventType.PayloadType; - return activity; + return result; }; var eventTypeDescriptor = activityDescriptor.Inputs.First(x => x.Name == nameof(WebhookEventReceived.EventType)); diff --git a/src/modules/persistence/Elsa.Persistence.Dapper.Migrations/Runtime/V3_7.cs b/src/modules/persistence/Elsa.Persistence.Dapper.Migrations/Runtime/V3_7.cs new file mode 100644 index 00000000..1c990c92 --- /dev/null +++ b/src/modules/persistence/Elsa.Persistence.Dapper.Migrations/Runtime/V3_7.cs @@ -0,0 +1,35 @@ +using System.Diagnostics.CodeAnalysis; +using FluentMigrator; +using JetBrains.Annotations; +using static System.Int32; + +namespace Elsa.Persistence.Dapper.Migrations.Runtime; + +/// +[Migration(20007, "Elsa:Runtime:V3.7")] +[PublicAPI] +[SuppressMessage("ReSharper", "InconsistentNaming")] +public class V3_7 : Migration +{ + /// + public override void Up() + { + Alter.Table("ActivityExecutionRecords").AddColumn("SerializedMetadata").AsString(MaxValue).Nullable(); + Alter.Table("ActivityExecutionRecords").AddColumn("SchedulingActivityExecutionId").AsString().Nullable(); + Alter.Table("ActivityExecutionRecords").AddColumn("SchedulingActivityId").AsString().Nullable(); + Alter.Table("ActivityExecutionRecords").AddColumn("SchedulingWorkflowInstanceId").AsString().Nullable(); + Alter.Table("ActivityExecutionRecords").AddColumn("CallStackDepth").AsInt32().Nullable(); + Alter.Table("ActivityExecutionRecords").AddColumn("AggregateFaultCount").AsInt32().NotNullable().WithDefaultValue(0); + } + + /// + public override void Down() + { + Delete.Column("SerializedMetadata").FromTable("ActivityExecutionRecords"); + Delete.Column("SchedulingActivityExecutionId").FromTable("ActivityExecutionRecords"); + Delete.Column("SchedulingActivityId").FromTable("ActivityExecutionRecords"); + Delete.Column("SchedulingWorkflowInstanceId").FromTable("ActivityExecutionRecords"); + Delete.Column("CallStackDepth").FromTable("ActivityExecutionRecords"); + Delete.Column("AggregateFaultCount").FromTable("ActivityExecutionRecords"); + } +} diff --git a/src/modules/persistence/Elsa.Persistence.Dapper/Modules/Runtime/Records/ActivityExecutionRecord.cs b/src/modules/persistence/Elsa.Persistence.Dapper/Modules/Runtime/Records/ActivityExecutionRecord.cs index 2b171b04..f9a9f413 100644 --- a/src/modules/persistence/Elsa.Persistence.Dapper/Modules/Runtime/Records/ActivityExecutionRecord.cs +++ b/src/modules/persistence/Elsa.Persistence.Dapper/Modules/Runtime/Records/ActivityExecutionRecord.cs @@ -62,6 +62,11 @@ internal class ActivityExecutionRecordRecord : Record /// public string? SerializedProperties { get; set; } + /// + /// Lightweight metadata associated with the activity execution. + /// + public string? SerializedMetadata { get; set; } + /// /// Gets or sets the time at which the activity execution began. /// @@ -76,9 +81,34 @@ internal class ActivityExecutionRecordRecord : Record /// Gets or sets the status of the activity. /// public string Status { get; set; } = null!; - + + /// + /// Gets or sets the aggregated count of faults encountered during the execution of the activity instance and its descendants. + /// + public int AggregateFaultCount { get; set; } + /// /// Gets or sets the time at which the activity execution completed. /// public DateTimeOffset? CompletedAt { get; set; } -} \ No newline at end of file + + /// + /// The ID of the activity execution context that scheduled this activity execution. + /// + public string? SchedulingActivityExecutionId { get; set; } + + /// + /// The ID of the activity that scheduled this activity execution (denormalized). + /// + public string? SchedulingActivityId { get; set; } + + /// + /// The workflow instance ID of the workflow that scheduled this activity execution. + /// + public string? SchedulingWorkflowInstanceId { get; set; } + + /// + /// The depth of this activity in the call stack (0 for root activities). + /// + public int? CallStackDepth { get; set; } +} diff --git a/src/modules/persistence/Elsa.Persistence.Dapper/Modules/Runtime/Records/ActivityExecutionSummaryRecord.cs b/src/modules/persistence/Elsa.Persistence.Dapper/Modules/Runtime/Records/ActivityExecutionSummaryRecord.cs index b0375695..834fb87c 100644 --- a/src/modules/persistence/Elsa.Persistence.Dapper/Modules/Runtime/Records/ActivityExecutionSummaryRecord.cs +++ b/src/modules/persistence/Elsa.Persistence.Dapper/Modules/Runtime/Records/ActivityExecutionSummaryRecord.cs @@ -51,9 +51,19 @@ internal class ActivityExecutionSummaryRecord : Record /// Gets or sets the status of the activity. /// public string Status { get; set; } = null!; + + /// + /// Lightweight metadata associated with the activity execution. + /// + public string? SerializedMetadata { get; set; } + + /// + /// Gets or sets the aggregated count of faults encountered during the execution of the activity instance and its descendants. + /// + public int AggregateFaultCount { get; set; } /// /// Gets or sets the time at which the activity execution completed. /// public DateTimeOffset? CompletedAt { get; set; } -} \ No newline at end of file +} diff --git a/src/modules/persistence/Elsa.Persistence.Dapper/Modules/Runtime/Stores/DapperActivityExecutionRecordStore.cs b/src/modules/persistence/Elsa.Persistence.Dapper/Modules/Runtime/Stores/DapperActivityExecutionRecordStore.cs index 5de5fafc..c2bace88 100644 --- a/src/modules/persistence/Elsa.Persistence.Dapper/Modules/Runtime/Stores/DapperActivityExecutionRecordStore.cs +++ b/src/modules/persistence/Elsa.Persistence.Dapper/Modules/Runtime/Stores/DapperActivityExecutionRecordStore.cs @@ -1,3 +1,4 @@ +using Elsa.Common.Models; using Elsa.Persistence.Dapper.Extensions; using Elsa.Persistence.Dapper.Models; using Elsa.Persistence.Dapper.Modules.Runtime.Records; @@ -88,6 +89,7 @@ public async Task DeleteManyAsync(ActivityExecutionRecordFilter filter, Ca return await store.DeleteAsync(q => ApplyFilter(q, filter), cancellationToken); } + private static void ApplyFilter(ParameterizedQuery query, ActivityExecutionRecordFilter filter) { query @@ -95,8 +97,21 @@ private static void ApplyFilter(ParameterizedQuery query, ActivityExecutionRecor .In(nameof(ActivityExecutionRecordRecord.Id), filter.Ids) .Is(nameof(ActivityExecutionRecordRecord.ActivityId), filter.ActivityId) .In(nameof(ActivityExecutionRecordRecord.ActivityId), filter.ActivityIds) + .Is(nameof(ActivityExecutionRecordRecord.ActivityNodeId), filter.ActivityNodeId) + .In(nameof(ActivityExecutionRecordRecord.ActivityNodeId), filter.ActivityNodeIds) + .Is(nameof(ActivityExecutionRecordRecord.ActivityName), filter.Name) + .In(nameof(ActivityExecutionRecordRecord.ActivityName), filter.Names) + .Is(nameof(ActivityExecutionRecordRecord.Status), filter.Status?.ToString()) + .In(nameof(ActivityExecutionRecordRecord.Status), filter.Statuses?.Select(x => x.ToString())) .Is(nameof(ActivityExecutionRecordRecord.WorkflowInstanceId), filter.WorkflowInstanceId) - .In(nameof(ActivityExecutionRecordRecord.WorkflowInstanceId), filter.WorkflowInstanceIds); + .In(nameof(ActivityExecutionRecordRecord.WorkflowInstanceId), filter.WorkflowInstanceIds) + .Is(nameof(ActivityExecutionRecordRecord.SchedulingActivityExecutionId), filter.SchedulingActivityExecutionId) + .In(nameof(ActivityExecutionRecordRecord.SchedulingActivityExecutionId), filter.SchedulingActivityExecutionIds) + .Is(nameof(ActivityExecutionRecordRecord.SchedulingActivityId), filter.SchedulingActivityId) + .In(nameof(ActivityExecutionRecordRecord.SchedulingActivityId), filter.SchedulingActivityIds) + .Is(nameof(ActivityExecutionRecordRecord.SchedulingWorkflowInstanceId), filter.SchedulingWorkflowInstanceId) + .In(nameof(ActivityExecutionRecordRecord.SchedulingWorkflowInstanceId), filter.SchedulingWorkflowInstanceIds) + .Is(nameof(ActivityExecutionRecordRecord.CallStackDepth), filter.CallStackDepth); if (filter.Completed != null) { @@ -127,6 +142,12 @@ private ActivityExecutionRecordRecord Map(ActivityExecutionRecord source) SerializedOutputs = source.Outputs?.Any() == true ? safeSerializer.Serialize(source.Outputs) : null, SerializedException = source.Exception != null ? payloadSerializer.Serialize(source.Exception) : null, SerializedProperties = source.Properties?.Any() == true ? safeSerializer.Serialize(source.Properties) : null, + SerializedMetadata = source.Metadata?.Any() == true ? payloadSerializer.Serialize(source.Metadata) : null, + AggregateFaultCount = source.AggregateFaultCount, + SchedulingActivityExecutionId = source.SchedulingActivityExecutionId, + SchedulingActivityId = source.SchedulingActivityId, + SchedulingWorkflowInstanceId = source.SchedulingWorkflowInstanceId, + CallStackDepth = source.CallStackDepth, TenantId = source.TenantId }; } @@ -151,6 +172,12 @@ private ActivityExecutionRecord Map(ActivityExecutionRecordRecord source) Outputs = source.SerializedOutputs != null ? safeSerializer.Deserialize>(source.SerializedOutputs) : null, Exception = source.SerializedException != null ? payloadSerializer.Deserialize(source.SerializedException) : null, Properties = source.SerializedProperties != null ? safeSerializer.Deserialize>(source.SerializedProperties) : null, + Metadata = source.SerializedMetadata != null ? payloadSerializer.Deserialize>(source.SerializedMetadata) : null, + AggregateFaultCount = source.AggregateFaultCount, + SchedulingActivityExecutionId = source.SchedulingActivityExecutionId, + SchedulingActivityId = source.SchedulingActivityId, + SchedulingWorkflowInstanceId = source.SchedulingWorkflowInstanceId, + CallStackDepth = source.CallStackDepth, TenantId = source.TenantId }; } @@ -170,7 +197,9 @@ private ActivityExecutionRecordSummary MapSummary(ActivityExecutionSummaryRecord HasBookmarks = source.HasBookmarks, Status = Enum.Parse(source.Status), ActivityTypeVersion = source.ActivityTypeVersion, + AggregateFaultCount = source.AggregateFaultCount, + Metadata = source.SerializedMetadata != null ? payloadSerializer.Deserialize>(source.SerializedMetadata) : null, TenantId = source.TenantId }; } -} \ No newline at end of file +} diff --git a/src/modules/persistence/Elsa.Persistence.MongoDb/Modules/Runtime/ActivityExecutionLogStore.cs b/src/modules/persistence/Elsa.Persistence.MongoDb/Modules/Runtime/ActivityExecutionLogStore.cs index 751af597..0c7d09ec 100644 --- a/src/modules/persistence/Elsa.Persistence.MongoDb/Modules/Runtime/ActivityExecutionLogStore.cs +++ b/src/modules/persistence/Elsa.Persistence.MongoDb/Modules/Runtime/ActivityExecutionLogStore.cs @@ -75,6 +75,7 @@ public Task DeleteManyAsync(ActivityExecutionRecordFilter filter, Cancella return mongoDbStore.DeleteWhereAsync(queryable => Filter(queryable, filter), x => x.Id, cancellationToken); } + private IQueryable Filter(IQueryable queryable, ActivityExecutionRecordFilter filter) { return filter.Apply(queryable); @@ -89,4 +90,4 @@ private IQueryable Paginate(IQueryable CreateMessageReceivedDescriptor(Type mess }, Constructor = context => { - var activity = context.CreateActivity(); + var result = context.CreateActivity(); + var activity = result.Activity; activity.Type = fullTypeName; activity.MessageType = messageType; - return activity; + return result; } }; } @@ -117,10 +118,11 @@ private async Task CreatePublishMessageDescriptor(Type messa }, Constructor = context => { - var activity = context.CreateActivity(); + var result = context.CreateActivity(); + var activity = result.Activity; activity.Type = fullTypeName; activity.MessageType = messageType; - return activity; + return result; } }; }