From 34c3d4e848eae3b8e2e335563a40c67e7325bd38 Mon Sep 17 00:00:00 2001 From: Behzad Alizadeh Date: Sun, 26 Apr 2026 19:47:19 +0330 Subject: [PATCH] Reset cache --- .../Controllers/WorkflowController.cs | 14 ++ .../appsettings.json | 4 +- .../Contracts/IWorkflowService.cs | 8 +- .../Services/WorkflowService.cs | 133 +++++++++++------- src/apps/Elsa.Server.Web/appsettings.json | 4 +- .../Elsa.ServerAndStudio.Web/appsettings.json | 3 +- .../Elsa.Caching/Contracts/ICacheManager.cs | 6 + .../Elsa.Caching/Services/CacheManager.cs | 11 +- 8 files changed, 122 insertions(+), 61 deletions(-) diff --git a/src/apps/Caspian.WorkflowFramework.Sample/Controllers/WorkflowController.cs b/src/apps/Caspian.WorkflowFramework.Sample/Controllers/WorkflowController.cs index b250896..f6112de 100644 --- a/src/apps/Caspian.WorkflowFramework.Sample/Controllers/WorkflowController.cs +++ b/src/apps/Caspian.WorkflowFramework.Sample/Controllers/WorkflowController.cs @@ -162,10 +162,24 @@ public class WorkflowController : Controller, ILoggable } #endregion + #region GetNextPossibleEvents [HttpPost("GetNextPossibleEvents")] public async Task>> GetNextPossibleEvents(string workflowInstanceId) { var result = await _workflowService.GetNextPossibleEventsAsync(workflowInstanceId); return Ok(result); + } + #endregion + + #region ResetCache + [HttpGet("ResetCache")] + public async Task ResetCache([FromQuery] string key) + { + _logger.Log("Start of ResetCache action", key); + + await _workflowService.EvictDefFromCacheAsync(key); + + _logger.Log("End of ResetCache action", key); } + #endregion } diff --git a/src/apps/Caspian.WorkflowFramework.Sample/appsettings.json b/src/apps/Caspian.WorkflowFramework.Sample/appsettings.json index 5940d74..fcfb280 100644 --- a/src/apps/Caspian.WorkflowFramework.Sample/appsettings.json +++ b/src/apps/Caspian.WorkflowFramework.Sample/appsettings.json @@ -40,7 +40,7 @@ "ConnectionStrings": { //"DefaultConnection": "Data Source=.;Initial Catalog=WfDb;User ID=sa;Password=123456;Integrated Security=false;TrustServerCertificate=True;" //"DefaultConnection": "Server=.;Database=CaspianWfDb;User Id=sa;Password=123456;TrustServerCertificate=True;" - //"DefaultConnection": "Server=.;Database=Workflow_Db;User Id=sa;Password=123456;TrustServerCertificate=True;" - "DefaultConnection": "Server=192.168.251.161;Database=Workflow_Db;User Id=sa;Password=cLL{3N29D@n2;MultipleActiveResultSets=true;TrustServerCertificate=True" + "DefaultConnection": "Server=.;Database=Workflow_Db;User Id=sa;Password=123456;TrustServerCertificate=True;" + //"DefaultConnection": "Server=192.168.251.161;Database=Workflow_Db;User Id=sa;Password=cLL{3N29D@n2;MultipleActiveResultSets=true;TrustServerCertificate=True" } } diff --git a/src/apps/Caspian.WorkflowFramework/Contracts/IWorkflowService.cs b/src/apps/Caspian.WorkflowFramework/Contracts/IWorkflowService.cs index f3f51be..7e299c1 100644 --- a/src/apps/Caspian.WorkflowFramework/Contracts/IWorkflowService.cs +++ b/src/apps/Caspian.WorkflowFramework/Contracts/IWorkflowService.cs @@ -54,8 +54,8 @@ public interface IWorkflowService Task> GetNextPossibleEventsAsync(string workflowInstanceId); - ///// - ///// Evicts a workflow definition from cache (optional, commented out in service). - ///// - //Task> EvictDefFromCacheAsync(string definitionId); + /// + /// Evicts a workflow definition from cache (optional, commented out in service). + /// + Task EvictDefFromCacheAsync(string name, CancellationToken cancellationToken = default); } diff --git a/src/apps/Caspian.WorkflowFramework/Services/WorkflowService.cs b/src/apps/Caspian.WorkflowFramework/Services/WorkflowService.cs index ff71582..c4b8a32 100644 --- a/src/apps/Caspian.WorkflowFramework/Services/WorkflowService.cs +++ b/src/apps/Caspian.WorkflowFramework/Services/WorkflowService.cs @@ -33,7 +33,6 @@ public class WorkflowService : IWorkflowService, ILoggable private readonly IEventPublisher _eventPublisher; private readonly IWorkflowDefinitionCacheManager _workflowDefinitionCacheManager; private readonly IMdbLogger _logger; - private readonly IBookmarkStore _bookmarkStore; private readonly IActivityExecutionStore _activityExecutionStore; #endregion @@ -49,9 +48,10 @@ public class WorkflowService : IWorkflowService, ILoggable _workflowInstanceManager = _serviceProvider.GetRequiredService(); _workflowInstanceStore = _serviceProvider.GetRequiredService(); _eventPublisher = _serviceProvider.GetRequiredService(); - _logger = logger; + _workflowDefinitionCacheManager = _serviceProvider.GetRequiredService(); _bookmarkStore = _serviceProvider.GetRequiredService(); _activityExecutionStore = _serviceProvider.GetRequiredService(); + _logger = logger; } #endregion @@ -136,6 +136,7 @@ public class WorkflowService : IWorkflowService, ILoggable sw.Stop(); + _logger.Log("Exception occurs in CreateAndExecuteAsync", WFInstanceId: response.Data?.InstanceId, response, sw.ElapsedMilliseconds, ex); return response; @@ -804,6 +805,7 @@ public class WorkflowService : IWorkflowService, ILoggable #endregion + #region GetNextPossibleEventsAsync public async Task> GetNextPossibleEventsAsync(string workflowInstanceId) { var sw = Stopwatch.StartNew(); @@ -915,66 +917,97 @@ public class WorkflowService : IWorkflowService, ILoggable return null; } + #endregion - //#region EvictDefFromCacheAsync - ///// - //public async Task> EvictDefFromCacheAsync(string definitionId) - //{ - // var sw = Stopwatch.StartNew(); - // try - // { - // _logger.Log("Start of EvictDefFromCacheAsync", definitionId); + #region EvictDefFromCacheAsync + /// + public async Task EvictDefFromCacheAsync(string name, CancellationToken cancellationToken = default) + { + var sw = Stopwatch.StartNew(); - // var key = _workflowDefinitionCacheManager.CreateWorkflowDefinitionChangeTokenKey(definitionId); - // await _workflowDefinitionCacheManager.EvictWorkflowDefinitionAsync(definitionId); + try + { + _logger.Log("Start of EvictDefFromCacheAsync", name); - // WorkflowResponse response; + var defFilter = new WorkflowDefinitionFilter() + { + Name = name, + VersionOptions = VersionOptions.Published + }; - // if (instance == null) - // { - // var msg = $"Workflow instance with id '{input.WorkflowInstanceId}' not found"; - // response = new WorkflowResponse() - // { - // Status = 1, - // Message = msg, - // Data = null - // }; + var definition = await _workflowDefinitionService + .FindWorkflowDefinitionAsync(defFilter); - // sw.Stop(); + //if (definition == null) + //{ + // _logger.Log("No definition found to evict", name); + // return; + //} - // _logger.Log("End of InquiryStateAsync", WFInstanceId: input.WorkflowInstanceId, response, sw.ElapsedMilliseconds); + //// 1. Evict definition cache + //await _workflowDefinitionCacheManager.EvictWorkflowDefinitionAsync(definition.DefinitionId, cancellationToken); + //_logger.Log($"Definition cache evicted for definitionId '{definition.DefinitionId}'", definition.DefinitionId); - // return response; - // } + //// 2. Re-index triggers (this rebuilds runtime cache) + //await _triggerIndexer.IndexTriggersAsync(definition, cancellationToken); + //_logger.Log($"Trigger indexing completed for definitionId '{definition.DefinitionId}'", definition.DefinitionId); - // response = new WorkflowResponse() - // { - // Status = 0, - // Message = "Success", - // Data = workflowModel - // }; + //var cacheKey = _workflowDefinitionCacheManager.CreateWorkflowFilterCacheKey(new WorkflowDefinitionFilter() + //{ + // DefinitionHandle = WorkflowDefinitionHandle.ByDefinitionId(definition.DefinitionId, VersionOptions.Published) + //}); - // sw.Stop(); + //await workflowDefinitionCacheManager.EvictWorkflowDefinitionAsync(notification.WorkflowDefinition.DefinitionId, cancellationToken); + //var cacheKey = cacheManager.CreateWorkflowDefinitionVersionCacheKey(definitionId, versionOptions); + //var cacheKey = cacheManager.CreateWorkflowDefinitionVersionCacheKey(definitionVersionId); + //var cacheKey = cacheManager.CreateWorkflowDefinitionFilterCacheKey(filter); + //var cacheKey = cacheManager.CreateWorkflowVersionCacheKey(definitionId, versionOptions); + //var cacheKey = cacheManager.CreateWorkflowVersionCacheKey(definitionVersionId); - // _logger.Log("End of InquiryStateAsync", WFInstanceId: input.WorkflowInstanceId, response, sw.ElapsedMilliseconds); - // return response; - // } - // catch (Exception ex) - // { - // var response = new WorkflowResponse() - // { - // Status = 100, - // Message = ex.Message, - // Data = null - // }; + //Definition cache + await _workflowDefinitionCacheManager.EvictWorkflowDefinitionAsync(definition.DefinitionId); - // sw.Stop(); + //Runtime Workflow Graph Cache + //await _notificationSender.SendAsync(new InvalidateWorkflowsCache()); + //await _workflowDefinitionsReloader.ReloadWorkflowDefinitionsAsync(); - // _logger.Log("Exception occurs in InquiryStateAsync", WFInstanceId: input.WorkflowInstanceId, response, sw.ElapsedMilliseconds, ex); + //Trigger Cache + //await _workflowDefinitionCacheManager.Cache.TriggerTokenAsync(CachingTriggerStore.CacheInvalidationTokenKey, cancellationToken); + //await _triggerIndexer.IndexTriggersAsync(definition); - // return response; - // } - //} - //#endregion + //_workflowDefinitionCacheManager.Cache.Remove("WorkflowDefinition:B0196B2A1FCF07CE8730A48F3E0238C6D8F52F7DB4C79A3C3B44A97C2BB10DB4"); + + var workflowDefinitionFilter = new WorkflowDefinitionFilter() + { + DefinitionHandle = WorkflowDefinitionHandle.ByDefinitionId(definition.DefinitionId, VersionOptions.Published) + }; + + var createWorkflowDefinitionFilterCacheKey = _workflowDefinitionCacheManager.CreateWorkflowDefinitionFilterCacheKey(workflowDefinitionFilter); + _workflowDefinitionCacheManager.Cache.Remove(createWorkflowDefinitionFilterCacheKey); + //await _workflowDefinitionCacheManager.Cache.TriggerTokenAsync(createWorkflowDefinitionFilterCacheKey); + + + var createWorkflowFilterCacheKey = _workflowDefinitionCacheManager.CreateWorkflowFilterCacheKey(workflowDefinitionFilter); + _workflowDefinitionCacheManager.Cache.Remove(createWorkflowFilterCacheKey); + //await _workflowDefinitionCacheManager.Cache.TriggerTokenAsync(createWorkflowFilterCacheKey); + + //_workflowDefinitionCacheManager.Cache.Remove("WorkflowDefinition:FAFFD28A8B17585222747A0B10C16311BCCAF7744F1C41274BBDC652356D99A6"); + //_workflowDefinitionCacheManager.Cache.Remove("Workflow:FAFFD28A8B17585222747A0B10C16311BCCAF7744F1C41274BBDC652356D99A6"); + + //_workflowDefinitionCacheManager.Cache.Remove("WorkflowDefinition:49B1E9FD1A0244512E8D2916B0A1B880E4473AA9F4E9341F6A69D331C9843B22"); + //_workflowDefinitionCacheManager.Cache.Remove("Workflow:49B1E9FD1A0244512E8D2916B0A1B880E4473AA9F4E9341F6A69D331C9843B22"); + + //_workflowDefinitionCacheManager.Cache.Remove("Workflow:398a80072c638a83"); + + + } + finally + { + sw.Stop(); + _logger.Log("End of EvictDefFromCacheAsync", name, sw.ElapsedMilliseconds, null); + } + } + + #endregion } \ No newline at end of file diff --git a/src/apps/Elsa.Server.Web/appsettings.json b/src/apps/Elsa.Server.Web/appsettings.json index b56021d..5598fa9 100644 --- a/src/apps/Elsa.Server.Web/appsettings.json +++ b/src/apps/Elsa.Server.Web/appsettings.json @@ -40,8 +40,8 @@ "Sqlite": "", //"Data Source=App_Data/elsa.sqlite.db;Cache=Shared;", //"SqlServer": "Server=localhost,1433;Initial Catalog=Elsa;User=sa;Password=!Elsa2025@;Encrypt=false;PersistSecurityInfo=false", //"SqlServer": "Server=.;Database=CaspianWfDb;User Id=sa;Password=123456;TrustServerCertificate=True;", - //"SqlServer": "Server=.;Database=Workflow_Db;User Id=sa;Password=123456;TrustServerCertificate=True;", - "SqlServer": "Server=192.168.251.161;Database=Workflow_Db;User Id=sa;Password=cLL{3N29D@n2;MultipleActiveResultSets=true;TrustServerCertificate=True", + "SqlServer": "Server=.;Database=Workflow_Db;User Id=sa;Password=123456;TrustServerCertificate=True;", + //"SqlServer": "Server=192.168.251.161;Database=Workflow_Db;User Id=sa;Password=cLL{3N29D@n2;MultipleActiveResultSets=true;TrustServerCertificate=True", "MySql": "", //"Server=localhost;Database=elsa;Uid=admin;Pwd=password;", "PostgreSql": "", //"Server=localhost;Username=elsa;Database=elsa;Port=5432;Password=elsa;SSLMode=Prefer;MaxPoolSize=2000;Timeout=60", "Citus": "", //"Server=localhost;Username=citus;Database=citus;Port=9700;Password=citus;SSLMode=Prefer;MaxPoolSize=2000;Timeout=60", diff --git a/src/apps/Elsa.ServerAndStudio.Web/appsettings.json b/src/apps/Elsa.ServerAndStudio.Web/appsettings.json index 3f4d61f..bfb99d3 100644 --- a/src/apps/Elsa.ServerAndStudio.Web/appsettings.json +++ b/src/apps/Elsa.ServerAndStudio.Web/appsettings.json @@ -39,7 +39,8 @@ "Sqlite": "", //"Data Source=elsa.sqlite.db;Cache=Shared;", "RabbitMq": "", //"rabbitmq://guest:guest@localhost:5672", "MySql": "", //"Server=localhost;Database=elsa;Uid=user;Pwd=password;", - "SqlServer": "Server=.;Database=WfDb;User Id=sa;Password=123456;TrustServerCertificate=True;", + //"SqlServer": "Server=.;Database=WfDb;User Id=sa;Password=123456;TrustServerCertificate=True;", + "SqlServer": "Server=192.168.251.161;Database=Workflow_Db;User Id=sa;Password=cLL{3N29D@n2;MultipleActiveResultSets=true;TrustServerCertificate=True", "PostgreSql": "" //"Server=localhost;Username=elsa;Database=elsa;Port=5432;Password=elsa;SSLMode=Prefer;MaxPoolSize=2000;Timeout=60" }, "DatabaseProvider": "SqlServer", //"Sqlite", diff --git a/src/modules/Elsa.Caching/Contracts/ICacheManager.cs b/src/modules/Elsa.Caching/Contracts/ICacheManager.cs index 6e93fe8..29deac5 100644 --- a/src/modules/Elsa.Caching/Contracts/ICacheManager.cs +++ b/src/modules/Elsa.Caching/Contracts/ICacheManager.cs @@ -29,4 +29,10 @@ public interface ICacheManager /// Gets an item from the cache, or creates it if it doesn't exist. /// Task GetOrCreateAsync(object key, Func> factory); + + /// + /// remove an item from the cache + /// + /// + void Remove(string key); } \ No newline at end of file diff --git a/src/modules/Elsa.Caching/Services/CacheManager.cs b/src/modules/Elsa.Caching/Services/CacheManager.cs index 6db5013..df0aa41 100644 --- a/src/modules/Elsa.Caching/Services/CacheManager.cs +++ b/src/modules/Elsa.Caching/Services/CacheManager.cs @@ -22,10 +22,17 @@ public class CacheManager(IMemoryCache memoryCache, IChangeTokenSignaler changeT { return changeTokenSignaler.TriggerTokenAsync(key, cancellationToken); } - + /// public async Task GetOrCreateAsync(object key, Func> factory) { - return await memoryCache.GetOrCreateAsync(key, async entry => await factory(entry)); + var result = await memoryCache.GetOrCreateAsync(key, async entry => await factory(entry)); + return result; + } + + /// + public void Remove(string key) + { + memoryCache.Remove(key); } } \ No newline at end of file