< 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>
 18418public class LocalWorkflowClient(
 18419    string workflowInstanceId,
 18420    IWorkflowInstanceManager workflowInstanceManager,
 18421    IWorkflowDefinitionService workflowDefinitionService,
 18422    IWorkflowRunner workflowRunner,
 18423    IWorkflowCanceler workflowCanceler,
 18424    WorkflowStateMapper workflowStateMapper,
 18425    ILogger<LocalWorkflowClient> logger) : IWorkflowClient
 26{
 27    /// <inheritdoc />
 44828    public string WorkflowInstanceId => workflowInstanceId;
 29
 30    /// <inheritdoc />
 31    public async Task<CreateWorkflowInstanceResponse> CreateInstanceAsync(CreateWorkflowInstanceRequest request, Cancell
 32    {
 3433        var workflowDefinitionHandle = request.WorkflowDefinitionHandle;
 3434        var workflowGraph = await GetWorkflowGraphAsync(workflowDefinitionHandle, cancellationToken);
 35
 3436        var options = new WorkflowInstanceOptions
 3437        {
 3438            WorkflowInstanceId = WorkflowInstanceId,
 3439            CorrelationId = request.CorrelationId,
 3440            Name = request.Name,
 3441            ParentWorkflowInstanceId = request.ParentId,
 3442            Input = request.Input,
 3443            Properties = request.Properties
 3444        };
 45
 3446        await workflowInstanceManager.CreateAndCommitWorkflowInstanceAsync(workflowGraph.Workflow, options, cancellation
 3447        return new();
 3448    }
 49
 50    /// <inheritdoc />
 51    public async Task<RunWorkflowInstanceResponse> RunInstanceAsync(RunWorkflowInstanceRequest request, CancellationToke
 52    {
 7853        var workflowInstance = await GetWorkflowInstanceAsync(cancellationToken);
 7854        return await RunInstanceAsync(workflowInstance, request, cancellationToken);
 7855    }
 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    {
 175133        var workflowState = workflowInstance.WorkflowState;
 134
 175135        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
 175146        var runWorkflowOptions = new RunWorkflowOptions
 175147        {
 175148            Input = request.Input,
 175149            Variables = request.Variables,
 175150            Properties = request.Properties,
 175151            BookmarkId = request.BookmarkId,
 175152            TriggerActivityId = request.TriggerActivityId,
 175153            ActivityHandle = request.ActivityHandle,
 175154        };
 155
 175156        var workflowGraph = await GetWorkflowGraphAsync(workflowInstance, cancellationToken);
 175157        var workflowResult = await workflowRunner.RunAsync(workflowGraph, workflowState, runWorkflowOptions, cancellatio
 158
 175159        workflowState = workflowResult.WorkflowState;
 160
 175161        return new()
 175162        {
 175163            WorkflowInstanceId = WorkflowInstanceId,
 175164            Status = workflowState.Status,
 175165            SubStatus = workflowState.SubStatus,
 175166            Incidents = workflowState.Incidents,
 175167            Output = request.IncludeWorkflowOutput ? new Dictionary<string, object>(workflowState.Output) : null,
 175168            Bookmarks = workflowState.Bookmarks
 175169        };
 175170    }
 171
 172    public async Task<WorkflowInstance> CreateInstanceInternalAsync(CreateWorkflowInstanceRequest request, CancellationT
 173    {
 97174        var workflowDefinitionHandle = request.WorkflowDefinitionHandle;
 97175        var workflowGraph = await GetWorkflowGraphAsync(workflowDefinitionHandle, cancellationToken);
 176
 97177        var options = new WorkflowInstanceOptions
 97178        {
 97179            WorkflowInstanceId = WorkflowInstanceId,
 97180            CorrelationId = request.CorrelationId,
 97181            Name = request.Name,
 97182            ParentWorkflowInstanceId = request.ParentId,
 97183            Input = request.Input,
 97184            Properties = request.Properties
 97185        };
 186
 97187        return workflowInstanceManager.CreateWorkflowInstance(workflowGraph.Workflow, options);
 97188    }
 189
 190    private async Task<WorkflowInstance> GetWorkflowInstanceAsync(CancellationToken cancellationToken)
 191    {
 134192        var workflowInstance = await TryGetWorkflowInstanceAsync(cancellationToken);
 134193        if (workflowInstance == null) throw new WorkflowInstanceNotFoundException("Workflow instance not found.", Workfl
 134194        return workflowInstance;
 134195    }
 196
 197    private Task<WorkflowInstance?> TryGetWorkflowInstanceAsync(CancellationToken cancellationToken)
 198    {
 142199        return workflowInstanceManager.FindByIdAsync(WorkflowInstanceId, cancellationToken);
 200    }
 201
 202    private async Task<WorkflowGraph> GetWorkflowGraphAsync(WorkflowInstance workflowInstance, CancellationToken cancell
 203    {
 180204        var handle = WorkflowDefinitionHandle.ByDefinitionVersionId(workflowInstance.DefinitionVersionId);
 180205        return await GetWorkflowGraphAsync(handle, cancellationToken);
 180206    }
 207
 208    private async Task<WorkflowGraph> GetWorkflowGraphAsync(WorkflowDefinitionHandle definitionHandle, CancellationToken
 209    {
 311210        var workflowGraph = await workflowDefinitionService.FindWorkflowGraphAsync(definitionHandle, cancellationToken);
 311211        if (workflowGraph == null) throw new WorkflowGraphNotFoundException("Workflow graph not found.", definitionHandl
 311212        return workflowGraph;
 311213    }
 214}