From 855c98282f2998783ea988f615a474a33f629f6a Mon Sep 17 00:00:00 2001 From: colin Date: Sat, 14 Mar 2026 14:44:13 +0800 Subject: [PATCH] feat: Workspace change synchronization event --- .../Chats/ConversationExpiredHandler.cs | 42 ++++++++++++++ ...orkspaceDefinitionStoreCacheInvalidator.cs | 58 +++++++++++++++++++ 2 files changed, 100 insertions(+) create mode 100644 aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain/LINGYUN/Abp/AIManagement/Chats/ConversationExpiredHandler.cs create mode 100644 aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain/LINGYUN/Abp/AIManagement/Workspaces/DynamicWorkspaceDefinitionStoreCacheInvalidator.cs diff --git a/aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain/LINGYUN/Abp/AIManagement/Chats/ConversationExpiredHandler.cs b/aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain/LINGYUN/Abp/AIManagement/Chats/ConversationExpiredHandler.cs new file mode 100644 index 000000000..8368ad019 --- /dev/null +++ b/aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain/LINGYUN/Abp/AIManagement/Chats/ConversationExpiredHandler.cs @@ -0,0 +1,42 @@ +using LINGYUN.Abp.AIManagement.Workspaces; +using System.Threading.Tasks; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Domain.Entities.Events; +using Volo.Abp.EventBus; +using Volo.Abp.Specifications; +using Volo.Abp.Timing; + +namespace LINGYUN.Abp.AIManagement.Chats; + +public class ConversationExpiredHandler : + ILocalEventHandler>, + ITransientDependency +{ + private readonly IClock _clock; + private readonly IConversationRecordRepository _conversationRecordRepository; + + public ConversationExpiredHandler( + IClock clock, + IConversationRecordRepository conversationRecordRepository) + { + _clock = clock; + _conversationRecordRepository = conversationRecordRepository; + } + + public async virtual Task HandleEventAsync(EntityDeletedEventData eventData) + { + var specification = new ExpressionSpecification( + x => x.Workspace == eventData.Entity.Name); + + var totalCount = await _conversationRecordRepository.GetCountAsync(specification); + var conversations = await _conversationRecordRepository.GetListAsync(specification, + maxResultCount: totalCount); + + foreach (var conversation in conversations ) + { + conversation.ExpiredAt = _clock.Now; + } + + await _conversationRecordRepository.UpdateManyAsync(conversations); + } +} diff --git a/aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain/LINGYUN/Abp/AIManagement/Workspaces/DynamicWorkspaceDefinitionStoreCacheInvalidator.cs b/aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain/LINGYUN/Abp/AIManagement/Workspaces/DynamicWorkspaceDefinitionStoreCacheInvalidator.cs new file mode 100644 index 000000000..69f705602 --- /dev/null +++ b/aspnet-core/modules/ai/LINGYUN.Abp.AIManagement.Domain/LINGYUN/Abp/AIManagement/Workspaces/DynamicWorkspaceDefinitionStoreCacheInvalidator.cs @@ -0,0 +1,58 @@ +using Microsoft.Extensions.Caching.Distributed; +using Microsoft.Extensions.Options; +using System; +using System.Threading.Tasks; +using Volo.Abp.Caching; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Domain.Entities.Events; +using Volo.Abp.EventBus; +using Volo.Abp.Threading; +using Volo.Abp.Timing; + +namespace LINGYUN.Abp.AIManagement.Workspaces; + +public class DynamicWorkspaceDefinitionStoreCacheInvalidator : + ILocalEventHandler>, + ITransientDependency +{ + private readonly IDynamicWorkspaceDefinitionStoreInMemoryCache _storeCache; + + private readonly IClock _clock; + private readonly IDistributedCache _distributedCache; + private readonly AbpDistributedCacheOptions _cacheOptions; + + public DynamicWorkspaceDefinitionStoreCacheInvalidator( + IClock clock, + IDistributedCache distributedCache, + IDynamicWorkspaceDefinitionStoreInMemoryCache storeCache, + IOptions cacheOptions) + { + _storeCache = storeCache; + _clock = clock; + _distributedCache = distributedCache; + _cacheOptions = cacheOptions.Value; + } + + public async virtual Task HandleEventAsync(EntityChangedEventData eventData) + { + await RemoveStampInDistributedCacheAsync(); + } + + protected async virtual Task RemoveStampInDistributedCacheAsync() + { + using (await _storeCache.SyncSemaphore.LockAsync()) + { + var cacheKey = GetCommonStampCacheKey(); + + await _distributedCache.RemoveAsync(cacheKey); + + _storeCache.CacheStamp = Guid.NewGuid().ToString(); + _storeCache.LastCheckTime = _clock.Now.AddMinutes(-5); + } + } + + protected virtual string GetCommonStampCacheKey() + { + return $"{_cacheOptions.KeyPrefix}_AbpInMemoryWorkspaceCacheStamp"; + } +}