< Summary

Information
Class: Elsa.Resilience.ResilientActivityInvoker
Assembly: Elsa.Resilience.Core
File(s): /home/runner/work/elsa-core/elsa-core/src/modules/Elsa.Resilience.Core/Services/ResilientActivityInvoker.cs
Line coverage
100%
Covered lines: 48
Uncovered lines: 0
Coverable lines: 48
Total lines: 116
Line coverage: 100%
Branch coverage
100%
Covered branches: 6
Total branches: 6
Branch coverage: 100%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%11100%
InvokeAsync()100%22100%
<InvokeAsync()100%11100%
RecordRetryAttempts()100%22100%
CreateResiliencePipelineBuilder()100%11100%
GetStrategyConfig(...)100%22100%
Map(...)100%11100%
Map(...)100%11100%

File(s)

/home/runner/work/elsa-core/elsa-core/src/modules/Elsa.Resilience.Core/Services/ResilientActivityInvoker.cs

#LineLine coverage
 1using System.Text.Json;
 2using Elsa.Expressions.Helpers;
 3using Elsa.Extensions;
 4using Elsa.Resilience.Entities;
 5using Elsa.Resilience.Extensions;
 6using Elsa.Resilience.Models;
 7using Elsa.Resilience.Serialization;
 8using Elsa.Workflows;
 9using Elsa.Workflows.State;
 10using Polly;
 11using Polly.Telemetry;
 12
 13namespace Elsa.Resilience;
 14
 1315public class ResilientActivityInvoker(
 1316    IResilienceStrategyConfigEvaluator resilienceStrategyConfigEvaluator,
 1317    IRetryAttemptRecorder retryAttemptRecorder,
 1318    IIdentityGenerator identityGenerator,
 1319    ResilienceStrategySerializer resilienceStrategySerializer) : IResilientActivityInvoker
 20{
 21    private const string ResilienceStrategyIdPropKey = "resilienceStrategy";
 22    private const string RetryAttemptsCountKey = "RetryAttemptsCount";
 23
 24    public async Task<T> InvokeAsync<T>(IResilientActivity activity, ActivityExecutionContext context, Func<Task<T>> act
 25    {
 26        // Get the resilience strategy.
 1327        var strategyConfig = GetStrategyConfig(activity);
 1328        var resilienceStrategy = await resilienceStrategyConfigEvaluator.EvaluateAsync(strategyConfig, context.Expressio
 29
 30        // If no resilience strategy is configured, execute the action as-is.
 1331        if (resilienceStrategy == null)
 432            return await action();
 33
 34        // Record the applied strategy as part of the activity execution context for diagnostics.
 935        var resilienceStrategyModel = JsonSerializer.SerializeToNode(resilienceStrategy, resilienceStrategySerializer.Se
 936        context.SetResilienceStrategy(resilienceStrategyModel);
 37
 38        // Create a resilience pipeline builder.
 939        var builder = CreateResiliencePipelineBuilder<T>();
 940        var retries = new List<RetryAttempt>();
 941        context.TransientProperties[RetryAttempt.RetriesKey] = retries;
 42
 43        // Create a resilience context.
 944        var resilienceContext = ResilienceContextPool.Shared.Get(cancellationToken);
 945        resilienceContext.Properties.Set(new(nameof(ActivityExecutionContext)), context);
 46
 47        try
 48        {
 49            // Configure the resilience pipeline.
 950            await resilienceStrategy.ConfigurePipeline(builder, resilienceContext);
 951            var pipeline = builder.Build();
 52
 53            // Execute the action within the resilience pipeline.
 2754            var result = await pipeline.ExecuteAsync<T>(async _ => await action(), resilienceContext);
 55
 56            // Record the retry attempts.
 757            await RecordRetryAttempts(activity, context, retries, cancellationToken);
 58
 759            return result;
 60        }
 61        finally
 62        {
 963            ResilienceContextPool.Shared.Return(resilienceContext);
 64        }
 65
 1166    }
 67
 68    private async Task RecordRetryAttempts(IResilientActivity activity, ActivityExecutionContext context, ICollection<Re
 69    {
 770        if (attempts.Count > 0)
 71        {
 572            var records = Map(context, activity, attempts);
 573            var recordContext = new RecordRetryAttemptsContext(context, records, cancellationToken);
 574            await retryAttemptRecorder.RecordAsync(recordContext);
 75
 76            // Propagate a flag that retries have occurred. This information can then be used to show the retry attempts
 577            context.SetRetriesAttemptedFlag();
 78
 579            context.SetExtensionsMetadata(RetryAttemptsCountKey, attempts.Count);
 80        }
 781    }
 82
 83    private ResiliencePipelineBuilder<T> CreateResiliencePipelineBuilder<T>()
 84    {
 985        var telemetryOptions = new TelemetryOptions();
 986        telemetryOptions.TelemetryListeners.Add(new RetryTelemetryListener());
 987        return new ResiliencePipelineBuilder<T>().ConfigureTelemetry(telemetryOptions);
 88    }
 89
 90    private ResilienceStrategyConfig? GetStrategyConfig(IResilientActivity resilientActivity)
 91    {
 1392        return !resilientActivity.CustomProperties.TryGetValue(ResilienceStrategyIdPropKey, out var value)
 1393            ? null
 1394            : value.ConvertTo<ResilienceStrategyConfig>();
 95    }
 96
 97    private ICollection<RetryAttemptRecord> Map(ActivityExecutionContext activityExecutionContext, IResilientActivity re
 98    {
 1299        return attempts.Select(x => Map(activityExecutionContext, resilientActivity, x)).ToList();
 100    }
 101
 102    private RetryAttemptRecord Map(ActivityExecutionContext activityExecutionContext, IResilientActivity resilientActivi
 103    {
 35104        var details = resilientActivity.CollectRetryDetails(activityExecutionContext, attempt).Where(x => x.Value != nul
 7105        return new()
 7106        {
 7107            Id = identityGenerator.GenerateId(),
 7108            ActivityInstanceId = activityExecutionContext.Id,
 7109            ActivityId = activityExecutionContext.Activity.Id,
 7110            WorkflowInstanceId = activityExecutionContext.WorkflowExecutionContext.Id,
 7111            AttemptNumber = attempt.AttemptNumber,
 7112            RetryDelay = attempt.RetryDelay,
 7113            Details = details
 7114        };
 115    }
 116}