< 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>
 18919public class LocalWorkflowClient(
 18920    string workflowInstanceId,
 18921    IWorkflowInstanceManager workflowInstanceManager,
 18922    IWorkflowDefinitionService workflowDefinitionService,
 18923    IWorkflowRunner workflowRunner,
 18924    IWorkflowCanceler workflowCanceler,
 18925    WorkflowStateMapper workflowStateMapper,
 18926    ILogger<LocalWorkflowClient> logger) : IWorkflowClient
 27{
 28    /// <inheritdoc />
 45129    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    {
 4761        var createRequest = new CreateWorkflowInstanceRequest
 4762        {
 4763            Properties = request.Properties,
 4764            CorrelationId = request.CorrelationId,
 4765            Name = request.Name,
 4766            Input = request.Input,
 4767            WorkflowDefinitionHandle = request.WorkflowDefinitionHandle,
 4768            ParentId = request.ParentId
 4769        };
 4770        var workflowInstance = await CreateInstanceInternalAsync(createRequest, cancellationToken);
 4571        return await RunInstanceAsync(workflowInstance, new()
 4572        {
 4573            Input = request.Input,
 4574            Variables = request.Variables,
 4575            Properties = request.Properties,
 4576            TriggerActivityId = request.TriggerActivityId,
 4577            ActivityHandle = request.ActivityHandle,
 4578            IncludeWorkflowOutput = request.IncludeWorkflowOutput,
 4579            SchedulingActivityExecutionId = request.SchedulingActivityExecutionId,
 4580            SchedulingWorkflowInstanceId = request.SchedulingWorkflowInstanceId,
 4581            SchedulingCallStackDepth = request.SchedulingCallStackDepth
 4582        }, cancellationToken);
 4583    }
 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    {
 56103        var workflowInstance = await GetWorkflowInstanceAsync(cancellationToken);
 56104        return workflowInstance.WorkflowState;
 56105    }
 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    {
 176137        var workflowState = workflowInstance.WorkflowState;
 138
 176139        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
 176150        var runWorkflowOptions = new RunWorkflowOptions
 176151        {
 176152            Input = request.Input,
 176153            Variables = request.Variables,
 176154            Properties = request.Properties,
 176155            BookmarkId = request.BookmarkId,
 176156            TriggerActivityId = request.TriggerActivityId,
 176157            ActivityHandle = request.ActivityHandle,
 176158            SchedulingActivityExecutionId = request.SchedulingActivityExecutionId,
 176159            SchedulingWorkflowInstanceId = request.SchedulingWorkflowInstanceId,
 176160            SchedulingCallStackDepth = request.SchedulingCallStackDepth
 176161        };
 162
 176163        var workflowGraph = await GetWorkflowGraphAsync(workflowInstance, cancellationToken);
 176164        var workflowResult = await workflowRunner.RunAsync(workflowGraph, workflowState, runWorkflowOptions, cancellatio
 165
 176166        workflowState = workflowResult.WorkflowState;
 167
 176168        return new()
 176169        {
 176170            WorkflowInstanceId = WorkflowInstanceId,
 176171            Status = workflowState.Status,
 176172            SubStatus = workflowState.SubStatus,
 176173            Incidents = workflowState.Incidents,
 176174            Output = request.IncludeWorkflowOutput ? new Dictionary<string, object>(workflowState.Output) : null,
 176175            Bookmarks = workflowState.Bookmarks
 176176        };
 176177    }
 178
 179    public async Task<WorkflowInstance> CreateInstanceInternalAsync(CreateWorkflowInstanceRequest request, CancellationT
 180    {
 100181        var workflowDefinitionHandle = request.WorkflowDefinitionHandle;
 100182        var workflowGraph = await GetWorkflowGraphAsync(workflowDefinitionHandle, cancellationToken);
 183
 98184        var options = new WorkflowInstanceOptions
 98185        {
 98186            WorkflowInstanceId = WorkflowInstanceId,
 98187            CorrelationId = request.CorrelationId,
 98188            Name = request.Name,
 98189            ParentWorkflowInstanceId = request.ParentId,
 98190            Input = request.Input,
 98191            Properties = request.Properties
 98192        };
 193
 98194        return workflowInstanceManager.CreateWorkflowInstance(workflowGraph.Workflow, options);
 98195    }
 196
 197    private async Task<WorkflowInstance> GetWorkflowInstanceAsync(CancellationToken cancellationToken)
 198    {
 135199        var workflowInstance = await TryGetWorkflowInstanceAsync(cancellationToken);
 135200        if (workflowInstance == null) throw new WorkflowInstanceNotFoundException("Workflow instance not found.", Workfl
 135201        return workflowInstance;
 135202    }
 203
 204    private Task<WorkflowInstance?> TryGetWorkflowInstanceAsync(CancellationToken cancellationToken)
 205    {
 143206        return workflowInstanceManager.FindByIdAsync(WorkflowInstanceId, cancellationToken);
 207    }
 208
 209    private async Task<WorkflowGraph> GetWorkflowGraphAsync(WorkflowInstance workflowInstance, CancellationToken cancell
 210    {
 181211        var handle = WorkflowDefinitionHandle.ByDefinitionVersionId(workflowInstance.DefinitionVersionId);
 181212        return await GetWorkflowGraphAsync(handle, cancellationToken);
 181213    }
 214
 215    private async Task<WorkflowGraph> GetWorkflowGraphAsync(WorkflowDefinitionHandle definitionHandle, CancellationToken
 216    {
 317217        var result = await workflowDefinitionService.TryFindWorkflowGraphAsync(definitionHandle, cancellationToken);
 319218        if (!result.WorkflowDefinitionExists) throw new WorkflowDefinitionNotFoundException("Workflow definition not fou
 317219        if (!result.WorkflowGraphExists) throw new WorkflowMaterializerNotFoundException(result.WorkflowDefinition!.Mate
 313220        return result.WorkflowGraph!;
 313221    }
 222}