using Elsa.Caching.Contracts; using Elsa.Caching.Options; using Elsa.Http.Bookmarks; using Elsa.Http.Contracts; using Elsa.Workflows.Activities; using Elsa.Workflows.Contracts; using Elsa.Workflows.Helpers; using Elsa.Workflows.Management.Contracts; using Elsa.Workflows.Runtime.Contracts; using Elsa.Workflows.Runtime.Entities; using Elsa.Workflows.Runtime.Filters; using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.Options; using Open.Linq.AsyncExtensions; namespace Elsa.Http.Services; /// public class HttpWorkflowsCacheManager( IMemoryCache memoryCache, ITriggerStore triggerStore, IWorkflowDefinitionService workflowDefinitionService, IChangeTokenSignaler changeTokenSignaler, IOptions cachingOptions) : IHttpWorkflowsCacheManager { /// public async Task<(Workflow? Workflow, ICollection Triggers)?> FindWorkflowAsync(string bookmarkHash, CancellationToken cancellationToken = default) { var key = $"workflow:{bookmarkHash}"; return await memoryCache.GetOrCreateAsync(key, async entry => { entry.SetSlidingExpiration(cachingOptions.Value.CacheDuration); entry.AddExpirationToken(changeTokenSignaler.GetToken(GetTriggerChangeTokenKey(bookmarkHash))); var triggers = await FindTriggersAsync(bookmarkHash, cancellationToken).ToList(); if (triggers.Count > 1) return (default, triggers); var trigger = triggers.SingleOrDefault(); if (trigger == null) return default; var workflow = await FindWorkflowAsync(trigger, cancellationToken); if (workflow == null) return default; var changeTokenKey = GetWorkflowChangeTokenKey(workflow.Identity.DefinitionId); var changeToken = changeTokenSignaler.GetToken(changeTokenKey); entry.AddExpirationToken(changeToken); return (workflow, triggers); }); } /// public async Task EvictWorkflowAsync(string workflowDefinitionId, CancellationToken cancellationToken = default) { var changeTokenKey = GetWorkflowChangeTokenKey(workflowDefinitionId); await changeTokenSignaler.TriggerTokenAsync(changeTokenKey, cancellationToken); } /// public async Task EvictTriggerAsync(string bookmarkHash, CancellationToken cancellationToken = default) { var changeTokenKey = GetTriggerChangeTokenKey(bookmarkHash); await changeTokenSignaler.TriggerTokenAsync(changeTokenKey, cancellationToken); } private async Task> FindTriggersAsync(string bookmarkHash, CancellationToken cancellationToken) { var triggerFilter = new TriggerFilter { Hash = bookmarkHash }; return await triggerStore.FindManyAsync(triggerFilter, cancellationToken); } private async Task FindWorkflowAsync(StoredTrigger trigger, CancellationToken cancellationToken) { var workflowDefinitionVersionId = trigger.WorkflowDefinitionVersionId; return await workflowDefinitionService.FindWorkflowAsync(workflowDefinitionVersionId, cancellationToken); } private string GetWorkflowChangeTokenKey(string workflowDefinitionId) => $"{GetType().FullName}:workflow:{workflowDefinitionId}:changeToken"; private string GetTriggerChangeTokenKey(string bookmarkHash) => $"{GetType().FullName}:trigger:{bookmarkHash}:changeToken"; }