Browse Source

Merge pull request #19288 from abpframework/tenant-cache-problem

Tenant cache problem fixed
pull/19304/head
oykuermann 3 years ago
committed by GitHub
parent
commit
81ed5274a2
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 16
      framework/src/Volo.Abp.MultiTenancy.Abstractions/Volo/Abp/MultiTenancy/TenantChangedEvent.cs
  2. 11
      modules/tenant-management/src/Volo.Abp.TenantManagement.Application/Volo/Abp/TenantManagement/TenantAppService.cs
  3. 18
      modules/tenant-management/src/Volo.Abp.TenantManagement.Domain/Volo/Abp/TenantManagement/TenantConfigurationCacheItemInvalidator.cs
  4. 12
      modules/tenant-management/src/Volo.Abp.TenantManagement.Domain/Volo/Abp/TenantManagement/TenantManager.cs
  5. 55
      modules/tenant-management/test/Volo.Abp.TenantManagement.Application.Tests/Volo/Abp/TenantManagement/TenantAppService_Tests.cs

16
framework/src/Volo.Abp.MultiTenancy.Abstractions/Volo/Abp/MultiTenancy/TenantChangedEvent.cs

@ -0,0 +1,16 @@
using System;
namespace Volo.Abp.MultiTenancy;
[Serializable]
public class TenantChangedEvent
{
public Guid? Id { get; set; }
public string? NormalizedName { get; set; }
public TenantChangedEvent(Guid? id = null, string? normalizedName = null)
{
Id = id;
NormalizedName = normalizedName;
}
}

11
modules/tenant-management/src/Volo.Abp.TenantManagement.Application/Volo/Abp/TenantManagement/TenantAppService.cs

@ -5,6 +5,7 @@ using Microsoft.AspNetCore.Authorization;
using Volo.Abp.Application.Dtos; using Volo.Abp.Application.Dtos;
using Volo.Abp.Data; using Volo.Abp.Data;
using Volo.Abp.EventBus.Distributed; using Volo.Abp.EventBus.Distributed;
using Volo.Abp.EventBus.Local;
using Volo.Abp.MultiTenancy; using Volo.Abp.MultiTenancy;
using Volo.Abp.ObjectExtending; using Volo.Abp.ObjectExtending;
@ -17,17 +18,20 @@ public class TenantAppService : TenantManagementAppServiceBase, ITenantAppServic
protected ITenantRepository TenantRepository { get; } protected ITenantRepository TenantRepository { get; }
protected ITenantManager TenantManager { get; } protected ITenantManager TenantManager { get; }
protected IDistributedEventBus DistributedEventBus { get; } protected IDistributedEventBus DistributedEventBus { get; }
protected ILocalEventBus LocalEventBus { get; }
public TenantAppService( public TenantAppService(
ITenantRepository tenantRepository, ITenantRepository tenantRepository,
ITenantManager tenantManager, ITenantManager tenantManager,
IDataSeeder dataSeeder, IDataSeeder dataSeeder,
IDistributedEventBus distributedEventBus) IDistributedEventBus distributedEventBus,
ILocalEventBus localEventBus)
{ {
DataSeeder = dataSeeder; DataSeeder = dataSeeder;
TenantRepository = tenantRepository; TenantRepository = tenantRepository;
TenantManager = tenantManager; TenantManager = tenantManager;
DistributedEventBus = distributedEventBus; DistributedEventBus = distributedEventBus;
LocalEventBus = localEventBus;
} }
public virtual async Task<TenantDto> GetAsync(Guid id) public virtual async Task<TenantDto> GetAsync(Guid id)
@ -132,6 +136,10 @@ public class TenantAppService : TenantManagementAppServiceBase, ITenantAppServic
public virtual async Task UpdateDefaultConnectionStringAsync(Guid id, string defaultConnectionString) public virtual async Task UpdateDefaultConnectionStringAsync(Guid id, string defaultConnectionString)
{ {
var tenant = await TenantRepository.GetAsync(id); var tenant = await TenantRepository.GetAsync(id);
if (tenant.FindDefaultConnectionString() != defaultConnectionString)
{
await LocalEventBus.PublishAsync(new TenantChangedEvent(tenant.Id, tenant.NormalizedName));
}
tenant.SetDefaultConnectionString(defaultConnectionString); tenant.SetDefaultConnectionString(defaultConnectionString);
await TenantRepository.UpdateAsync(tenant); await TenantRepository.UpdateAsync(tenant);
} }
@ -141,6 +149,7 @@ public class TenantAppService : TenantManagementAppServiceBase, ITenantAppServic
{ {
var tenant = await TenantRepository.GetAsync(id); var tenant = await TenantRepository.GetAsync(id);
tenant.RemoveDefaultConnectionString(); tenant.RemoveDefaultConnectionString();
await LocalEventBus.PublishAsync(new TenantChangedEvent(tenant.Id, tenant.NormalizedName));
await TenantRepository.UpdateAsync(tenant); await TenantRepository.UpdateAsync(tenant);
} }
} }

18
modules/tenant-management/src/Volo.Abp.TenantManagement.Domain/Volo/Abp/TenantManagement/TenantConfigurationCacheItemInvalidator.cs

@ -4,14 +4,16 @@ using Volo.Abp.Caching;
using Volo.Abp.DependencyInjection; using Volo.Abp.DependencyInjection;
using Volo.Abp.Domain.Entities.Events; using Volo.Abp.Domain.Entities.Events;
using Volo.Abp.EventBus; using Volo.Abp.EventBus;
using Volo.Abp.EventBus.Local;
using Volo.Abp.MultiTenancy; using Volo.Abp.MultiTenancy;
namespace Volo.Abp.TenantManagement; namespace Volo.Abp.TenantManagement;
[LocalEventHandlerOrder(-1)]
public class TenantConfigurationCacheItemInvalidator : public class TenantConfigurationCacheItemInvalidator :
ILocalEventHandler<EntityChangedEventData<Tenant>>, ILocalEventHandler<EntityChangedEventData<Tenant>>,
ILocalEventHandler<EntityDeletedEventData<Tenant>>, ITransientDependency ILocalEventHandler<TenantChangedEvent>,
ITransientDependency
{ {
protected IDistributedCache<TenantConfigurationCacheItem> Cache { get; } protected IDistributedCache<TenantConfigurationCacheItem> Cache { get; }
@ -22,12 +24,17 @@ public class TenantConfigurationCacheItemInvalidator :
public virtual async Task HandleEventAsync(EntityChangedEventData<Tenant> eventData) public virtual async Task HandleEventAsync(EntityChangedEventData<Tenant> eventData)
{ {
if (eventData is EntityCreatedEventData<Tenant>)
{
return;
}
await ClearCacheAsync(eventData.Entity.Id, eventData.Entity.NormalizedName); await ClearCacheAsync(eventData.Entity.Id, eventData.Entity.NormalizedName);
} }
public virtual async Task HandleEventAsync(EntityDeletedEventData<Tenant> eventData) public virtual async Task HandleEventAsync(TenantChangedEvent eventData)
{ {
await ClearCacheAsync(eventData.Entity.Id, eventData.Entity.NormalizedName); await ClearCacheAsync(eventData.Id, eventData.NormalizedName);
} }
protected virtual async Task ClearCacheAsync(Guid? id, string normalizedName) protected virtual async Task ClearCacheAsync(Guid? id, string normalizedName)
@ -37,6 +44,7 @@ public class TenantConfigurationCacheItemInvalidator :
{ {
TenantConfigurationCacheItem.CalculateCacheKey(id, null), TenantConfigurationCacheItem.CalculateCacheKey(id, null),
TenantConfigurationCacheItem.CalculateCacheKey(null, normalizedName), TenantConfigurationCacheItem.CalculateCacheKey(null, normalizedName),
TenantConfigurationCacheItem.CalculateCacheKey(id, normalizedName),
}); });
} }
} }

12
modules/tenant-management/src/Volo.Abp.TenantManagement.Domain/Volo/Abp/TenantManagement/TenantManager.cs

@ -2,6 +2,7 @@
using System.Threading.Tasks; using System.Threading.Tasks;
using Volo.Abp.Caching; using Volo.Abp.Caching;
using Volo.Abp.Domain.Services; using Volo.Abp.Domain.Services;
using Volo.Abp.EventBus.Local;
using Volo.Abp.MultiTenancy; using Volo.Abp.MultiTenancy;
namespace Volo.Abp.TenantManagement; namespace Volo.Abp.TenantManagement;
@ -9,14 +10,17 @@ namespace Volo.Abp.TenantManagement;
public class TenantManager : DomainService, ITenantManager public class TenantManager : DomainService, ITenantManager
{ {
protected ITenantRepository TenantRepository { get; } protected ITenantRepository TenantRepository { get; }
protected IDistributedCache<TenantConfigurationCacheItem> Cache { get; }
protected ITenantNormalizer TenantNormalizer { get; } protected ITenantNormalizer TenantNormalizer { get; }
protected ILocalEventBus LocalEventBus { get; }
public TenantManager(ITenantRepository tenantRepository, IDistributedCache<TenantConfigurationCacheItem> cache, ITenantNormalizer tenantNormalizer) public TenantManager(
ITenantRepository tenantRepository,
ITenantNormalizer tenantNormalizer,
ILocalEventBus localEventBus)
{ {
TenantRepository = tenantRepository; TenantRepository = tenantRepository;
Cache = cache;
TenantNormalizer = tenantNormalizer; TenantNormalizer = tenantNormalizer;
LocalEventBus = localEventBus;
} }
public virtual async Task<Tenant> CreateAsync(string name) public virtual async Task<Tenant> CreateAsync(string name)
@ -36,7 +40,7 @@ public class TenantManager : DomainService, ITenantManager
var normalizedName = TenantNormalizer.NormalizeName(name); var normalizedName = TenantNormalizer.NormalizeName(name);
await ValidateNameAsync(normalizedName, tenant.Id); await ValidateNameAsync(normalizedName, tenant.Id);
await Cache.RemoveAsync(TenantConfigurationCacheItem.CalculateCacheKey(tenant.NormalizedName)); await LocalEventBus.PublishAsync(new TenantChangedEvent(tenant.Id, tenant.NormalizedName));
tenant.SetName(name); tenant.SetName(name);
tenant.SetNormalizedName(normalizedName); tenant.SetNormalizedName(normalizedName);
} }

55
modules/tenant-management/test/Volo.Abp.TenantManagement.Application.Tests/Volo/Abp/TenantManagement/TenantAppService_Tests.cs

@ -2,6 +2,9 @@
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Shouldly; using Shouldly;
using Volo.Abp.Caching;
using Volo.Abp.MultiTenancy;
using Volo.Abp.Uow;
using Xunit; using Xunit;
namespace Volo.Abp.TenantManagement; namespace Volo.Abp.TenantManagement;
@ -9,10 +12,20 @@ namespace Volo.Abp.TenantManagement;
public class TenantAppService_Tests : AbpTenantManagementApplicationTestBase public class TenantAppService_Tests : AbpTenantManagementApplicationTestBase
{ {
private readonly ITenantAppService _tenantAppService; private readonly ITenantAppService _tenantAppService;
private readonly IUnitOfWorkManager _unitOfWorkManager;
private readonly IDistributedCache<TenantConfigurationCacheItem> _cache;
private readonly ITenantStore _tenantStore;
private readonly ITenantRepository _tenantRepository;
private readonly ITenantNormalizer _tenantNormalizer;
public TenantAppService_Tests() public TenantAppService_Tests()
{ {
_tenantAppService = GetRequiredService<ITenantAppService>(); _tenantAppService = GetRequiredService<ITenantAppService>();
_unitOfWorkManager = GetRequiredService<IUnitOfWorkManager>();
_cache = GetRequiredService<IDistributedCache<TenantConfigurationCacheItem>>();
_tenantStore = GetRequiredService<ITenantStore>();
_tenantRepository = GetRequiredService<ITenantRepository>();
_tenantNormalizer = GetRequiredService<ITenantNormalizer>();
} }
[Fact] [Fact]
@ -108,4 +121,46 @@ public class TenantAppService_Tests : AbpTenantManagementApplicationTestBase
dbContext.Tenants.Any(t => t.Id == acme.Id).ShouldBeFalse(); dbContext.Tenants.Any(t => t.Id == acme.Id).ShouldBeFalse();
}); });
} }
[Fact]
public async Task Cache_Should_Invalidator_When_Tenant_ConnectionString_Changed()
{
var acme = await _tenantRepository.FindByNameAsync(_tenantNormalizer.NormalizeName("acme"));
// UpdateDefaultConnectionStringAsync
// FindAsync will cache tenant.
await _tenantStore.FindAsync(acme.Id);
await _tenantStore.FindAsync(acme.NormalizedName);
(await _cache.GetAsync(TenantConfigurationCacheItem.CalculateCacheKey(acme.Id, null))).ShouldNotBeNull();
(await _cache.GetAsync(TenantConfigurationCacheItem.CalculateCacheKey(null, acme.NormalizedName))).ShouldNotBeNull();
using (var uow = _unitOfWorkManager.Begin(requiresNew: true))
{
await _tenantAppService.UpdateDefaultConnectionStringAsync(acme.Id, Guid.NewGuid().ToString());
await uow.CompleteAsync();
}
(await _cache.GetAsync(TenantConfigurationCacheItem.CalculateCacheKey(acme.Id, null))).ShouldBeNull();
(await _cache.GetAsync(TenantConfigurationCacheItem.CalculateCacheKey(null, acme.NormalizedName))).ShouldBeNull();
// DeleteDefaultConnectionStringAsync
// FindAsync will cache tenant.
await _tenantStore.FindAsync(acme.Id);
await _tenantStore.FindAsync(acme.NormalizedName);
(await _cache.GetAsync(TenantConfigurationCacheItem.CalculateCacheKey(acme.Id, null))).ShouldNotBeNull();
(await _cache.GetAsync(TenantConfigurationCacheItem.CalculateCacheKey(null, acme.NormalizedName))).ShouldNotBeNull();
using (var uow = _unitOfWorkManager.Begin(requiresNew: true))
{
await _tenantAppService.DeleteDefaultConnectionStringAsync(acme.Id);
await uow.CompleteAsync();
}
(await _cache.GetAsync(TenantConfigurationCacheItem.CalculateCacheKey(acme.Id, null))).ShouldBeNull();
(await _cache.GetAsync(TenantConfigurationCacheItem.CalculateCacheKey(null, acme.NormalizedName))).ShouldBeNull();
}
} }

Loading…
Cancel
Save