< Summary

Information
Class: Elsa.Workflows.Runtime.LocalWorkflowClient
Assembly: Elsa.Workflows.Runtime
File(s): /home/runner/work/elsa-core/elsa-core/src/modules/Elsa.Workflows.Runtime/Services/LocalWorkflowClient.cs
Line coverage
93%
Covered lines: 117
Uncovered lines: 8
Coverable lines: 125
Total lines: 214
Line coverage: 93.6%
Branch coverage
66%
Covered branches: 8
Total branches: 12
Branch coverage: 66.6%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%11100%
get_WorkflowInstanceId()100%11100%
CreateInstanceAsync()100%11100%
RunInstanceAsync()100%11100%
CreateAndRunInstanceAsync()100%11100%
CancelAsync()100%11100%
CancelAsync()100%22100%
ExportStateAsync()100%11100%
ImportStateAsync()100%11100%
InstanceExistsAsync(...)100%210%
DeleteAsync()100%22100%
RunInstanceAsync()50%4477.41%
CreateInstanceInternalAsync()100%11100%
GetWorkflowInstanceAsync()50%22100%
TryGetWorkflowInstanceAsync(...)100%11100%
GetWorkflowGraphAsync()100%11100%
GetWorkflowGraphAsync()50%22100%

File(s)

/home/runner/work/elsa-core/elsa-core/src/modules/Elsa.Workflows.Runtime/Services/LocalWorkflowClient.cs

#LineLine coverage
 1using Elsa.Workflows.Management;
 2using Elsa.Workflows.Management.Entities;
 3using Elsa.Workflows.Management.Filters;
 4using Elsa.Workflows.Management.Mappers;
 5using Elsa.Workflows.Management.Options;
 6using Elsa.Workflows.Models;
 7using Elsa.Workflows.Options;
 8using Elsa.Workflows.Runtime.Exceptions;
 9using Elsa.Workflows.Runtime.Messages;
 10using Elsa.Workflows.State;
 11using Microsoft.Extensions.Logging;
 12
 13namespace Elsa.Workflows.Runtime;
 14
 15/// <summary>
 16/// Represents a client for executing and managing local workflows.
 17/// </summary>
 17018public class LocalWorkflowClient(
 17019    string workflowInstanceId,
 17020    IWorkflowInstanceManager workflowInstanceManager,
 17021    IWorkflowDefinitionService workflowDefinitionService,
 17022    IWorkflowRunner workflowRunner,
 17023    IWorkflowCanceler workflowCanceler,
 17024    WorkflowStateMapper workflowStateMapper,
 17025    ILogger<LocalWorkflowClient> logger) : IWorkflowClient
 26{
 27    /// <inheritdoc />
 41228    public string WorkflowInstanceId => workflowInstanceId;
 29
 30    /// <inheritdoc />
 31    public async Task<CreateWorkflowInstanceResponse> CreateInstanceAsync(CreateWorkflowInstanceRequest request, Cancell
 32    {
 2433        var workflowDefinitionHandle = request.WorkflowDefinitionHandle;
 2434        var workflowGraph = await GetWorkflowGraphAsync(workflowDefinitionHandle, cancellationToken);
 35
 2436        var options = new WorkflowInstanceOptions
 2437        {
 2438            WorkflowInstanceId = WorkflowInstanceId,
 2439            CorrelationId = request.CorrelationId,
 2440            Name = request.Name,
 2441            ParentWorkflowInstanceId = request.ParentId,
 2442            Input = request.Input,
 2443            Properties = request.Properties
 2444        };
 45
 2446        await workflowInstanceManager.CreateAndCommitWorkflowInstanceAsync(workflowGraph.Workflow, options, cancellation
 2447        return new();
 2448    }
 49
 50    /// <inheritdoc />
 51    public async Task<RunWorkflowInstanceResponse> RunInstanceAsync(RunWorkflowInstanceRequest request, CancellationToke
 52    {
 6653        var workflowInstance = await GetWorkflowInstanceAsync(cancellationToken);
 6654        return await RunInstanceAsync(workflowInstance, request, cancellationToken);
 6655    }
 56
 57    /// <inheritdoc />
 58    public async Task<RunWorkflowInstanceResponse> CreateAndRunInstanceAsync(CreateAndRunWorkflowInstanceRequest request
 59    {
 4460        var createRequest = new CreateWorkflowInstanceRequest
 4461        {
 4462            Properties = request.Properties,
 4463            CorrelationId = request.CorrelationId,
 4464            Name = request.Name,
 4465            Input = request.Input,
 4466            WorkflowDefinitionHandle = request.WorkflowDefinitionHandle,
 4467            ParentId = request.ParentId
 4468        };
 4469        var workflowInstance = await CreateInstanceInternalAsync(createRequest, cancellationToken);
 4470        return await RunInstanceAsync(workflowInstance, new()
 4471        {
 4472            Input = request.Input,
 4473            Variables = request.Variables,
 4474            Properties = request.Properties,
 4475            TriggerActivityId = request.TriggerActivityId,
 4476            ActivityHandle = request.ActivityHandle,
 4477            IncludeWorkflowOutput = request.IncludeWorkflowOutput
 4478        }, cancellationToken);
 4479    }
 80
 81    /// <inheritdoc />
 82    public async Task CancelAsync(CancellationToken cancellationToken = default)
 83    {
 184        var workflowInstance = await GetWorkflowInstanceAsync(cancellationToken);
 185        await CancelAsync(workflowInstance, cancellationToken);
 186    }
 87
 88    private async Task CancelAsync(WorkflowInstance workflowInstance, CancellationToken cancellationToken)
 89    {
 1190        if (workflowInstance.Status != WorkflowStatus.Running) return;
 591        var workflowGraph = await GetWorkflowGraphAsync(workflowInstance, cancellationToken);
 592        var workflowState = await workflowCanceler.CancelWorkflowAsync(workflowGraph, workflowInstance.WorkflowState, ca
 593        await workflowInstanceManager.SaveAsync(workflowState, cancellationToken);
 894    }
 95
 96    /// <inheritdoc />
 97    public async Task<WorkflowState> ExportStateAsync(CancellationToken cancellationToken = default)
 98    {
 5599        var workflowInstance = await GetWorkflowInstanceAsync(cancellationToken);
 55100        return workflowInstance.WorkflowState;
 55101    }
 102
 103    /// <inheritdoc />
 104    public async Task ImportStateAsync(WorkflowState workflowState, CancellationToken cancellationToken = default)
 105    {
 1106        var workflowInstance = workflowStateMapper.Map(workflowState)!;
 1107        await workflowInstanceManager.SaveAsync(workflowInstance, cancellationToken);
 1108    }
 109
 110    public Task<bool> InstanceExistsAsync(CancellationToken cancellationToken = default)
 111    {
 0112        return workflowInstanceManager.ExistsAsync(workflowInstanceId, cancellationToken);
 113    }
 114
 115    /// <inheritdoc />
 116    public async Task<bool> DeleteAsync(CancellationToken cancellationToken = default)
 117    {
 118        // Load the workflow instance (single DB call)
 8119        var workflowInstance = await TryGetWorkflowInstanceAsync(cancellationToken);
 8120        if (workflowInstance == null)
 1121            return false;
 122
 7123        await CancelAsync(workflowInstance, cancellationToken);
 124
 125        // Delete the workflow instance
 7126        var filter = new WorkflowInstanceFilter { Id = workflowInstanceId };
 7127        await workflowInstanceManager.DeleteAsync(filter, cancellationToken);
 7128        return true;
 8129    }
 130
 131    public async Task<RunWorkflowInstanceResponse> RunInstanceAsync(WorkflowInstance workflowInstance, RunWorkflowInstan
 132    {
 162133        var workflowState = workflowInstance.WorkflowState;
 134
 162135        if (workflowInstance.Status != WorkflowStatus.Running)
 136        {
 0137            logger.LogWarning("Attempt to resume workflow {WorkflowInstanceId} that is not in the Running state. The act
 0138            return new()
 0139            {
 0140                WorkflowInstanceId = WorkflowInstanceId,
 0141                Status = workflowInstance.Status,
 0142                SubStatus = workflowInstance.SubStatus
 0143            };
 144        }
 145
 162146        var runWorkflowOptions = new RunWorkflowOptions
 162147        {
 162148            Input = request.Input,
 162149            Variables = request.Variables,
 162150            Properties = request.Properties,
 162151            BookmarkId = request.BookmarkId,
 162152            TriggerActivityId = request.TriggerActivityId,
 162153            ActivityHandle = request.ActivityHandle,
 162154        };
 155
 162156        var workflowGraph = await GetWorkflowGraphAsync(workflowInstance, cancellationToken);
 162157        var workflowResult = await workflowRunner.RunAsync(workflowGraph, workflowState, runWorkflowOptions, cancellatio
 158
 162159        workflowState = workflowResult.WorkflowState;
 160
 162161        return new()
 162162        {
 162163            WorkflowInstanceId = WorkflowInstanceId,
 162164            Status = workflowState.Status,
 162165            SubStatus = workflowState.SubStatus,
 162166            Incidents = workflowState.Incidents,
 162167            Output = request.IncludeWorkflowOutput ? new Dictionary<string, object>(workflowState.Output) : null,
 162168            Bookmarks = workflowState.Bookmarks
 162169        };
 162170    }
 171
 172    public async Task<WorkflowInstance> CreateInstanceInternalAsync(CreateWorkflowInstanceRequest request, CancellationT
 173    {
 96174        var workflowDefinitionHandle = request.WorkflowDefinitionHandle;
 96175        var workflowGraph = await GetWorkflowGraphAsync(workflowDefinitionHandle, cancellationToken);
 176
 96177        var options = new WorkflowInstanceOptions
 96178        {
 96179            WorkflowInstanceId = WorkflowInstanceId,
 96180            CorrelationId = request.CorrelationId,
 96181            Name = request.Name,
 96182            ParentWorkflowInstanceId = request.ParentId,
 96183            Input = request.Input,
 96184            Properties = request.Properties
 96185        };
 186
 96187        return workflowInstanceManager.CreateWorkflowInstance(workflowGraph.Workflow, options);
 96188    }
 189
 190    private async Task<WorkflowInstance> GetWorkflowInstanceAsync(CancellationToken cancellationToken)
 191    {
 122192        var workflowInstance = await TryGetWorkflowInstanceAsync(cancellationToken);
 122193        if (workflowInstance == null) throw new WorkflowInstanceNotFoundException("Workflow instance not found.", Workfl
 122194        return workflowInstance;
 122195    }
 196
 197    private Task<WorkflowInstance?> TryGetWorkflowInstanceAsync(CancellationToken cancellationToken)
 198    {
 130199        return workflowInstanceManager.FindByIdAsync(WorkflowInstanceId, cancellationToken);
 200    }
 201
 202    private async Task<WorkflowGraph> GetWorkflowGraphAsync(WorkflowInstance workflowInstance, CancellationToken cancell
 203    {
 167204        var handle = WorkflowDefinitionHandle.ByDefinitionVersionId(workflowInstance.DefinitionVersionId);
 167205        return await GetWorkflowGraphAsync(handle, cancellationToken);
 167206    }
 207
 208    private async Task<WorkflowGraph> GetWorkflowGraphAsync(WorkflowDefinitionHandle definitionHandle, CancellationToken
 209    {
 287210        var workflowGraph = await workflowDefinitionService.FindWorkflowGraphAsync(definitionHandle, cancellationToken);
 287211        if (workflowGraph == null) throw new WorkflowGraphNotFoundException("Workflow graph not found.", definitionHandl
 287212        return workflowGraph;
 287213    }
 214}