< 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: 124
Uncovered lines: 8
Coverable lines: 132
Total lines: 222
Line coverage: 93.9%
Branch coverage
71%
Covered branches: 10
Total branches: 14
Branch coverage: 71.4%
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%4479.41%
CreateInstanceInternalAsync()100%11100%
GetWorkflowInstanceAsync()50%22100%
TryGetWorkflowInstanceAsync(...)100%11100%
GetWorkflowGraphAsync()100%11100%
GetWorkflowGraphAsync()75%44100%

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.Exceptions;
 4using Elsa.Workflows.Management.Filters;
 5using Elsa.Workflows.Management.Mappers;
 6using Elsa.Workflows.Management.Options;
 7using Elsa.Workflows.Models;
 8using Elsa.Workflows.Options;
 9using Elsa.Workflows.Runtime.Exceptions;
 10using Elsa.Workflows.Runtime.Messages;
 11using Elsa.Workflows.State;
 12using Microsoft.Extensions.Logging;
 13
 14namespace Elsa.Workflows.Runtime;
 15
 16/// <summary>
 17/// Represents a client for executing and managing local workflows.
 18/// </summary>
 18819public class LocalWorkflowClient(
 18820    string workflowInstanceId,
 18821    IWorkflowInstanceManager workflowInstanceManager,
 18822    IWorkflowDefinitionService workflowDefinitionService,
 18823    IWorkflowRunner workflowRunner,
 18824    IWorkflowCanceler workflowCanceler,
 18825    WorkflowStateMapper workflowStateMapper,
 18826    ILogger<LocalWorkflowClient> logger) : IWorkflowClient
 27{
 28    /// <inheritdoc />
 44829    public string WorkflowInstanceId => workflowInstanceId;
 30
 31    /// <inheritdoc />
 32    public async Task<CreateWorkflowInstanceResponse> CreateInstanceAsync(CreateWorkflowInstanceRequest request, Cancell
 33    {
 3634        var workflowDefinitionHandle = request.WorkflowDefinitionHandle;
 3635        var workflowGraph = await GetWorkflowGraphAsync(workflowDefinitionHandle, cancellationToken);
 36
 3437        var options = new WorkflowInstanceOptions
 3438        {
 3439            WorkflowInstanceId = WorkflowInstanceId,
 3440            CorrelationId = request.CorrelationId,
 3441            Name = request.Name,
 3442            ParentWorkflowInstanceId = request.ParentId,
 3443            Input = request.Input,
 3444            Properties = request.Properties
 3445        };
 46
 3447        await workflowInstanceManager.CreateAndCommitWorkflowInstanceAsync(workflowGraph.Workflow, options, cancellation
 3448        return new();
 3449    }
 50
 51    /// <inheritdoc />
 52    public async Task<RunWorkflowInstanceResponse> RunInstanceAsync(RunWorkflowInstanceRequest request, CancellationToke
 53    {
 7854        var workflowInstance = await GetWorkflowInstanceAsync(cancellationToken);
 7855        return await RunInstanceAsync(workflowInstance, request, cancellationToken);
 7856    }
 57
 58    /// <inheritdoc />
 59    public async Task<RunWorkflowInstanceResponse> CreateAndRunInstanceAsync(CreateAndRunWorkflowInstanceRequest request
 60    {
 4661        var createRequest = new CreateWorkflowInstanceRequest
 4662        {
 4663            Properties = request.Properties,
 4664            CorrelationId = request.CorrelationId,
 4665            Name = request.Name,
 4666            Input = request.Input,
 4667            WorkflowDefinitionHandle = request.WorkflowDefinitionHandle,
 4668            ParentId = request.ParentId
 4669        };
 4670        var workflowInstance = await CreateInstanceInternalAsync(createRequest, cancellationToken);
 4471        return await RunInstanceAsync(workflowInstance, new()
 4472        {
 4473            Input = request.Input,
 4474            Variables = request.Variables,
 4475            Properties = request.Properties,
 4476            TriggerActivityId = request.TriggerActivityId,
 4477            ActivityHandle = request.ActivityHandle,
 4478            IncludeWorkflowOutput = request.IncludeWorkflowOutput,
 4479            SchedulingActivityExecutionId = request.SchedulingActivityExecutionId,
 4480            SchedulingWorkflowInstanceId = request.SchedulingWorkflowInstanceId,
 4481            SchedulingCallStackDepth = request.SchedulingCallStackDepth
 4482        }, cancellationToken);
 4483    }
 84
 85    /// <inheritdoc />
 86    public async Task CancelAsync(CancellationToken cancellationToken = default)
 87    {
 188        var workflowInstance = await GetWorkflowInstanceAsync(cancellationToken);
 189        await CancelAsync(workflowInstance, cancellationToken);
 190    }
 91
 92    private async Task CancelAsync(WorkflowInstance workflowInstance, CancellationToken cancellationToken)
 93    {
 1194        if (workflowInstance.Status != WorkflowStatus.Running) return;
 595        var workflowGraph = await GetWorkflowGraphAsync(workflowInstance, cancellationToken);
 596        var workflowState = await workflowCanceler.CancelWorkflowAsync(workflowGraph, workflowInstance.WorkflowState, ca
 597        await workflowInstanceManager.SaveAsync(workflowState, cancellationToken);
 898    }
 99
 100    /// <inheritdoc />
 101    public async Task<WorkflowState> ExportStateAsync(CancellationToken cancellationToken = default)
 102    {
 55103        var workflowInstance = await GetWorkflowInstanceAsync(cancellationToken);
 55104        return workflowInstance.WorkflowState;
 55105    }
 106
 107    /// <inheritdoc />
 108    public async Task ImportStateAsync(WorkflowState workflowState, CancellationToken cancellationToken = default)
 109    {
 1110        var workflowInstance = workflowStateMapper.Map(workflowState)!;
 1111        await workflowInstanceManager.SaveAsync(workflowInstance, cancellationToken);
 1112    }
 113
 114    public Task<bool> InstanceExistsAsync(CancellationToken cancellationToken = default)
 115    {
 0116        return workflowInstanceManager.ExistsAsync(workflowInstanceId, cancellationToken);
 117    }
 118
 119    /// <inheritdoc />
 120    public async Task<bool> DeleteAsync(CancellationToken cancellationToken = default)
 121    {
 122        // Load the workflow instance (single DB call)
 8123        var workflowInstance = await TryGetWorkflowInstanceAsync(cancellationToken);
 8124        if (workflowInstance == null)
 1125            return false;
 126
 7127        await CancelAsync(workflowInstance, cancellationToken);
 128
 129        // Delete the workflow instance
 7130        var filter = new WorkflowInstanceFilter { Id = workflowInstanceId };
 7131        await workflowInstanceManager.DeleteAsync(filter, cancellationToken);
 7132        return true;
 8133    }
 134
 135    public async Task<RunWorkflowInstanceResponse> RunInstanceAsync(WorkflowInstance workflowInstance, RunWorkflowInstan
 136    {
 175137        var workflowState = workflowInstance.WorkflowState;
 138
 175139        if (workflowInstance.Status != WorkflowStatus.Running)
 140        {
 0141            logger.LogWarning("Attempt to resume workflow {WorkflowInstanceId} that is not in the Running state. The act
 0142            return new()
 0143            {
 0144                WorkflowInstanceId = WorkflowInstanceId,
 0145                Status = workflowInstance.Status,
 0146                SubStatus = workflowInstance.SubStatus
 0147            };
 148        }
 149
 175150        var runWorkflowOptions = new RunWorkflowOptions
 175151        {
 175152            Input = request.Input,
 175153            Variables = request.Variables,
 175154            Properties = request.Properties,
 175155            BookmarkId = request.BookmarkId,
 175156            TriggerActivityId = request.TriggerActivityId,
 175157            ActivityHandle = request.ActivityHandle,
 175158            SchedulingActivityExecutionId = request.SchedulingActivityExecutionId,
 175159            SchedulingWorkflowInstanceId = request.SchedulingWorkflowInstanceId,
 175160            SchedulingCallStackDepth = request.SchedulingCallStackDepth
 175161        };
 162
 175163        var workflowGraph = await GetWorkflowGraphAsync(workflowInstance, cancellationToken);
 175164        var workflowResult = await workflowRunner.RunAsync(workflowGraph, workflowState, runWorkflowOptions, cancellatio
 165
 175166        workflowState = workflowResult.WorkflowState;
 167
 175168        return new()
 175169        {
 175170            WorkflowInstanceId = WorkflowInstanceId,
 175171            Status = workflowState.Status,
 175172            SubStatus = workflowState.SubStatus,
 175173            Incidents = workflowState.Incidents,
 175174            Output = request.IncludeWorkflowOutput ? new Dictionary<string, object>(workflowState.Output) : null,
 175175            Bookmarks = workflowState.Bookmarks
 175176        };
 175177    }
 178
 179    public async Task<WorkflowInstance> CreateInstanceInternalAsync(CreateWorkflowInstanceRequest request, CancellationT
 180    {
 99181        var workflowDefinitionHandle = request.WorkflowDefinitionHandle;
 99182        var workflowGraph = await GetWorkflowGraphAsync(workflowDefinitionHandle, cancellationToken);
 183
 97184        var options = new WorkflowInstanceOptions
 97185        {
 97186            WorkflowInstanceId = WorkflowInstanceId,
 97187            CorrelationId = request.CorrelationId,
 97188            Name = request.Name,
 97189            ParentWorkflowInstanceId = request.ParentId,
 97190            Input = request.Input,
 97191            Properties = request.Properties
 97192        };
 193
 97194        return workflowInstanceManager.CreateWorkflowInstance(workflowGraph.Workflow, options);
 97195    }
 196
 197    private async Task<WorkflowInstance> GetWorkflowInstanceAsync(CancellationToken cancellationToken)
 198    {
 134199        var workflowInstance = await TryGetWorkflowInstanceAsync(cancellationToken);
 134200        if (workflowInstance == null) throw new WorkflowInstanceNotFoundException("Workflow instance not found.", Workfl
 134201        return workflowInstance;
 134202    }
 203
 204    private Task<WorkflowInstance?> TryGetWorkflowInstanceAsync(CancellationToken cancellationToken)
 205    {
 142206        return workflowInstanceManager.FindByIdAsync(WorkflowInstanceId, cancellationToken);
 207    }
 208
 209    private async Task<WorkflowGraph> GetWorkflowGraphAsync(WorkflowInstance workflowInstance, CancellationToken cancell
 210    {
 180211        var handle = WorkflowDefinitionHandle.ByDefinitionVersionId(workflowInstance.DefinitionVersionId);
 180212        return await GetWorkflowGraphAsync(handle, cancellationToken);
 180213    }
 214
 215    private async Task<WorkflowGraph> GetWorkflowGraphAsync(WorkflowDefinitionHandle definitionHandle, CancellationToken
 216    {
 315217        var result = await workflowDefinitionService.TryFindWorkflowGraphAsync(definitionHandle, cancellationToken);
 317218        if (!result.WorkflowDefinitionExists) throw new WorkflowDefinitionNotFoundException("Workflow definition not fou
 315219        if (!result.WorkflowGraphExists) throw new WorkflowMaterializerNotFoundException(result.WorkflowDefinition!.Mate
 311220        return result.WorkflowGraph!;
 311221    }
 222}