< Summary

Information
Class: Elsa.Workflows.Management.Stores.MemoryWorkflowInstanceStore
Assembly: Elsa.Workflows.Management
File(s): /home/runner/work/elsa-core/elsa-core/src/modules/Elsa.Workflows.Management/Stores/MemoryWorkflowInstanceStore.cs
Line coverage
29%
Covered lines: 26
Uncovered lines: 63
Coverable lines: 89
Total lines: 226
Line coverage: 29.2%
Branch coverage
66%
Covered branches: 12
Total branches: 18
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%
FindAsync(...)100%11100%
FindManyAsync(...)100%210%
FindManyAsync(...)100%210%
FindManyAsync(...)100%210%
FindManyAsync(...)100%210%
CountAsync(...)100%210%
SummarizeManyAsync()100%210%
SummarizeManyAsync()100%210%
SummarizeManyAsync()100%210%
SummarizeManyAsync()100%210%
FindManyIdsAsync(...)100%210%
FindManyIdsAsync()100%210%
FindManyIdsAsync()0%620%
SaveAsync(...)100%11100%
AddAsync(...)100%210%
UpdateAsync(...)100%210%
SaveManyAsync(...)0%620%
DeleteAsync(...)100%210%
UpdateUpdatedTimestampAsync()0%620%
TryMarkInterruptedAsync(...)83.33%66100%
GetId(...)100%210%
get_CurrentTenantId()75%44100%
Filter(...)100%11100%
ApplyCurrentTenant(...)100%44100%

File(s)

/home/runner/work/elsa-core/elsa-core/src/modules/Elsa.Workflows.Management/Stores/MemoryWorkflowInstanceStore.cs

#LineLine coverage
 1using System.Diagnostics.CodeAnalysis;
 2using Elsa.Common.Models;
 3using Elsa.Common.Multitenancy;
 4using Elsa.Common.Services;
 5using Elsa.Extensions;
 6using Elsa.Workflows.Management.Entities;
 7using Elsa.Workflows.Management.Filters;
 8using Elsa.Workflows.Management.Models;
 9
 10namespace Elsa.Workflows.Management.Stores;
 11
 12/// <summary>
 13/// A non-persistent memory store for saving and loading <see cref="WorkflowInstance"/> entities.
 14/// </summary>
 15public class MemoryWorkflowInstanceStore : IWorkflowInstanceStore
 16{
 17    private readonly MemoryStore<WorkflowInstance> _store;
 18    private readonly ITenantAccessor? _tenantAccessor;
 20519    private readonly object _sync = new();
 20
 21    /// <summary>
 22    /// Constructor.
 23    /// </summary>
 20524    public MemoryWorkflowInstanceStore(MemoryStore<WorkflowInstance> store, ITenantAccessor? tenantAccessor = null)
 25    {
 20526        _store = store;
 20527        _tenantAccessor = tenantAccessor;
 20528    }
 29
 30    /// <inheritdoc />
 31    public ValueTask<WorkflowInstance?> FindAsync(WorkflowInstanceFilter filter, CancellationToken cancellationToken = d
 32    {
 41233        var entity = _store.Query(query => Filter(query, filter)).FirstOrDefault();
 20634        return ValueTask.FromResult(entity);
 35    }
 36
 37    /// <inheritdoc />
 38    public ValueTask<Page<WorkflowInstance>> FindManyAsync(WorkflowInstanceFilter filter, PageArgs pageArgs, Cancellatio
 39    {
 040        var count = _store.Query(query => Filter(query, filter)).LongCount();
 041        var entities = _store.Query(query => Filter(query, filter).Paginate(pageArgs)).ToList();
 042        var page = Page.Of(entities, count);
 043        return ValueTask.FromResult(page);
 44    }
 45
 46    /// <inheritdoc />
 47    public ValueTask<Page<WorkflowInstance>> FindManyAsync<TOrderBy>(WorkflowInstanceFilter filter, PageArgs pageArgs, W
 48    {
 049        var count = _store.Query(query => Filter(query, filter)).LongCount();
 050        var entities = _store.Query(query => Filter(query, filter).OrderBy(order).Paginate(pageArgs)).ToList();
 051        var page = Page.Of(entities, count);
 052        return ValueTask.FromResult(page);
 53    }
 54
 55    /// <inheritdoc />
 56    public ValueTask<IEnumerable<WorkflowInstance>> FindManyAsync(WorkflowInstanceFilter filter, CancellationToken cance
 57    {
 058        var entities = _store.Query(query => Filter(query, filter)).ToList().AsEnumerable();
 059        return ValueTask.FromResult(entities);
 60    }
 61
 62    /// <inheritdoc />
 63    public ValueTask<IEnumerable<WorkflowInstance>> FindManyAsync<TOrderBy>(WorkflowInstanceFilter filter, WorkflowInsta
 64    {
 065        var entities = _store.Query(query => Filter(query, filter).OrderBy(order)).ToList().AsEnumerable();
 066        return ValueTask.FromResult(entities);
 67    }
 68
 69    /// <inheritdoc />
 70    public ValueTask<long> CountAsync(WorkflowInstanceFilter filter, CancellationToken cancellationToken = default)
 71    {
 072        var count = _store.Query(query => Filter(query, filter)).LongCount();
 073        return new(count);
 74    }
 75
 76    /// <inheritdoc />
 77    public async ValueTask<Page<WorkflowInstanceSummary>> SummarizeManyAsync(WorkflowInstanceFilter filter, PageArgs pag
 78    {
 079        var page = await FindManyAsync(filter, pageArgs, cancellationToken);
 080        return new(page.Items.Select(WorkflowInstanceSummary.FromInstance).ToList(), page.TotalCount);
 081    }
 82
 83    /// <inheritdoc />
 84    public async ValueTask<Page<WorkflowInstanceSummary>> SummarizeManyAsync<TOrderBy>(WorkflowInstanceFilter filter, Pa
 85    {
 086        var page = await FindManyAsync(filter, pageArgs, order, cancellationToken);
 087        return new(page.Items.Select(WorkflowInstanceSummary.FromInstance).ToList(), page.TotalCount);
 088    }
 89
 90    /// <inheritdoc />
 91    public async ValueTask<IEnumerable<WorkflowInstanceSummary>> SummarizeManyAsync(WorkflowInstanceFilter filter, Cance
 92    {
 093        var entities = await FindManyAsync(filter, cancellationToken);
 094        return entities.Select(WorkflowInstanceSummary.FromInstance);
 095    }
 96
 97    /// <inheritdoc />
 98    public async ValueTask<IEnumerable<WorkflowInstanceSummary>> SummarizeManyAsync<TOrderBy>(WorkflowInstanceFilter fil
 99    {
 0100        var entities = await FindManyAsync(filter, order, cancellationToken);
 0101        return entities.Select(WorkflowInstanceSummary.FromInstance);
 0102    }
 103
 104    /// <inheritdoc />
 105    public ValueTask<IEnumerable<string>> FindManyIdsAsync(WorkflowInstanceFilter filter, CancellationToken cancellation
 106    {
 0107        var entities = _store.Query(query => Filter(query, filter)).Select(x => x.Id).ToList().AsEnumerable();
 0108        return ValueTask.FromResult(entities);
 109    }
 110
 111    /// <inheritdoc />
 112    public async ValueTask<Page<string>> FindManyIdsAsync(WorkflowInstanceFilter filter, PageArgs pageArgs, Cancellation
 113    {
 0114        var page = await FindManyAsync(filter, pageArgs, cancellationToken);
 0115        var ids = page.Items.Select(x => x.Id).ToList();
 0116        return new(ids, page.TotalCount);
 0117    }
 118
 119    /// <inheritdoc />
 120    public async ValueTask<Page<string>> FindManyIdsAsync<TOrderBy>(WorkflowInstanceFilter filter, PageArgs pageArgs, Wo
 121    {
 0122        var page = await FindManyAsync(filter, pageArgs, order, cancellationToken);
 0123        var ids = page.Items.Select(x => x.Id).ToList();
 0124        return new(ids, page.TotalCount);
 0125    }
 126
 127    /// <inheritdoc />
 128    public ValueTask SaveAsync(WorkflowInstance instance, CancellationToken cancellationToken = default)
 129    {
 406130        lock (_sync)
 131        {
 406132            ApplyCurrentTenant(instance);
 812133            _store.Save(instance, x => x.Id);
 406134        }
 406135        return ValueTask.CompletedTask;
 136    }
 137
 138    public ValueTask AddAsync(WorkflowInstance instance, CancellationToken cancellationToken = default)
 139    {
 0140        lock (_sync)
 141        {
 0142            ApplyCurrentTenant(instance);
 0143            _store.Add(instance, GetId);
 0144        }
 0145        return ValueTask.CompletedTask;
 146    }
 147
 148    public ValueTask UpdateAsync(WorkflowInstance instance, CancellationToken cancellationToken = default)
 149    {
 0150        lock (_sync)
 0151            _store.Update(instance, GetId);
 0152        return ValueTask.CompletedTask;
 153    }
 154
 155    /// <inheritdoc />
 156    public ValueTask SaveManyAsync(IEnumerable<WorkflowInstance> instances, CancellationToken cancellationToken = defaul
 157    {
 0158        lock (_sync)
 159        {
 0160            var instanceList = instances.ToList();
 0161            foreach (var instance in instanceList)
 0162                ApplyCurrentTenant(instance);
 0163            _store.SaveMany(instanceList, GetId);
 0164        }
 0165        return ValueTask.CompletedTask;
 166    }
 167
 168    /// <inheritdoc />
 169    public ValueTask<long> DeleteAsync(WorkflowInstanceFilter filter, CancellationToken cancellationToken = default)
 170    {
 0171        var query = Filter(_store.List().AsQueryable(), filter);
 0172        var count = _store.DeleteMany(query, x => x.Id);
 0173        return ValueTask.FromResult(count);
 174    }
 175
 176    /// <inheritdoc />
 177    public async Task UpdateUpdatedTimestampAsync(string workflowInstanceId, DateTimeOffset value, CancellationToken can
 178    {
 0179        var workflowInstance = await FindAsync(new()
 0180        {
 0181            Id = workflowInstanceId
 0182        }, cancellationToken);
 183
 0184        if (workflowInstance == null)
 0185            throw new InvalidOperationException($"Workflow instance with ID '{workflowInstanceId}' does not exist.");
 186
 0187        workflowInstance.UpdatedAt = value;
 0188    }
 189
 190    /// <inheritdoc />
 191    /// <remarks>
 192    /// <paramref name="allowFinishedCancelled"/> is unused: drain no longer promotes Finished/Cancelled (#8419).
 193    /// The parameter remains so the 3.8.4 signature stays binary-compatible.
 194    /// </remarks>
 195    public ValueTask<bool> TryMarkInterruptedAsync(string workflowInstanceId, CancellationToken cancellationToken = defa
 196    {
 197        // Same lock as Save/Update so a runner's terminal persist cannot land between the
 198        // tenant/status check and the Interrupted mutations. Every condition is evaluated
 199        // once inside this lock — then mutate, with nothing after.
 206200        lock (_sync)
 201        {
 412202            var instance = _store.Find(x => x.Id == workflowInstanceId && TenantVisibility.IsVisible(x.TenantId, Current
 206203            if (instance is null || instance.Status == WorkflowStatus.Finished)
 204204                return ValueTask.FromResult(false);
 205
 2206            instance.Status = WorkflowStatus.Running;
 2207            instance.SubStatus = WorkflowSubStatus.Interrupted;
 2208            instance.IsExecuting = false;
 2209            return ValueTask.FromResult(true);
 210        }
 206211    }
 212
 0213    private static string GetId(WorkflowInstance workflowInstance) => workflowInstance.Id;
 214
 818215    private string CurrentTenantId => _tenantAccessor?.TenantId ?? Tenant.DefaultTenantId;
 216
 217    [RequiresUnreferencedCode("Calls Elsa.Workflows.Management.Filters.WorkflowInstanceFilter.Apply(IQueryable<WorkflowI
 218    private IQueryable<WorkflowInstance> Filter(IQueryable<WorkflowInstance> query, WorkflowInstanceFilter filter) =>
 206219        filter.Apply(query.WhereVisibleToTenant(CurrentTenantId));
 220
 221    private void ApplyCurrentTenant(WorkflowInstance instance)
 222    {
 406223        if (instance.TenantId != Tenant.AgnosticTenantId)
 406224            instance.TenantId ??= CurrentTenantId;
 406225    }
 226}

Methods/Properties

.ctor(Elsa.Common.Services.MemoryStore`1<Elsa.Workflows.Management.Entities.WorkflowInstance>,Elsa.Common.Multitenancy.ITenantAccessor)
FindAsync(Elsa.Workflows.Management.Filters.WorkflowInstanceFilter,System.Threading.CancellationToken)
FindManyAsync(Elsa.Workflows.Management.Filters.WorkflowInstanceFilter,Elsa.Common.Models.PageArgs,System.Threading.CancellationToken)
FindManyAsync(Elsa.Workflows.Management.Filters.WorkflowInstanceFilter,Elsa.Common.Models.PageArgs,Elsa.Workflows.Management.Filters.WorkflowInstanceOrder`1<TOrderBy>,System.Threading.CancellationToken)
FindManyAsync(Elsa.Workflows.Management.Filters.WorkflowInstanceFilter,System.Threading.CancellationToken)
FindManyAsync(Elsa.Workflows.Management.Filters.WorkflowInstanceFilter,Elsa.Workflows.Management.Filters.WorkflowInstanceOrder`1<TOrderBy>,System.Threading.CancellationToken)
CountAsync(Elsa.Workflows.Management.Filters.WorkflowInstanceFilter,System.Threading.CancellationToken)
SummarizeManyAsync()
SummarizeManyAsync()
SummarizeManyAsync()
SummarizeManyAsync()
FindManyIdsAsync(Elsa.Workflows.Management.Filters.WorkflowInstanceFilter,System.Threading.CancellationToken)
FindManyIdsAsync()
FindManyIdsAsync()
SaveAsync(Elsa.Workflows.Management.Entities.WorkflowInstance,System.Threading.CancellationToken)
AddAsync(Elsa.Workflows.Management.Entities.WorkflowInstance,System.Threading.CancellationToken)
UpdateAsync(Elsa.Workflows.Management.Entities.WorkflowInstance,System.Threading.CancellationToken)
SaveManyAsync(System.Collections.Generic.IEnumerable`1<Elsa.Workflows.Management.Entities.WorkflowInstance>,System.Threading.CancellationToken)
DeleteAsync(Elsa.Workflows.Management.Filters.WorkflowInstanceFilter,System.Threading.CancellationToken)
UpdateUpdatedTimestampAsync()
TryMarkInterruptedAsync(System.String,System.Threading.CancellationToken,System.Boolean)
GetId(Elsa.Workflows.Management.Entities.WorkflowInstance)
get_CurrentTenantId()
Filter(System.Linq.IQueryable`1<Elsa.Workflows.Management.Entities.WorkflowInstance>,Elsa.Workflows.Management.Filters.WorkflowInstanceFilter)
ApplyCurrentTenant(Elsa.Workflows.Management.Entities.WorkflowInstance)