Skip to content

Commit

Permalink
Merge pull request #19288 from abpframework/tenant-cache-problem
Browse files Browse the repository at this point in the history
Tenant cache problem fixed
  • Loading branch information
oykuermann authored Mar 14, 2024
2 parents 59a1501 + 3ea7f9a commit 81ed527
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 10 deletions.
Original file line number Diff line number Diff line change
@@ -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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using Volo.Abp.Application.Dtos;
using Volo.Abp.Data;
using Volo.Abp.EventBus.Distributed;
using Volo.Abp.EventBus.Local;
using Volo.Abp.MultiTenancy;
using Volo.Abp.ObjectExtending;

Expand All @@ -17,17 +18,20 @@ public class TenantAppService : TenantManagementAppServiceBase, ITenantAppServic
protected ITenantRepository TenantRepository { get; }
protected ITenantManager TenantManager { get; }
protected IDistributedEventBus DistributedEventBus { get; }
protected ILocalEventBus LocalEventBus { get; }

public TenantAppService(
ITenantRepository tenantRepository,
ITenantManager tenantManager,
IDataSeeder dataSeeder,
IDistributedEventBus distributedEventBus)
IDistributedEventBus distributedEventBus,
ILocalEventBus localEventBus)
{
DataSeeder = dataSeeder;
TenantRepository = tenantRepository;
TenantManager = tenantManager;
DistributedEventBus = distributedEventBus;
LocalEventBus = localEventBus;
}

public virtual async Task<TenantDto> GetAsync(Guid id)
Expand Down Expand Up @@ -132,6 +136,10 @@ public virtual async Task<string> GetDefaultConnectionStringAsync(Guid id)
public virtual async Task UpdateDefaultConnectionStringAsync(Guid id, string defaultConnectionString)
{
var tenant = await TenantRepository.GetAsync(id);
if (tenant.FindDefaultConnectionString() != defaultConnectionString)
{
await LocalEventBus.PublishAsync(new TenantChangedEvent(tenant.Id, tenant.NormalizedName));
}
tenant.SetDefaultConnectionString(defaultConnectionString);
await TenantRepository.UpdateAsync(tenant);
}
Expand All @@ -141,6 +149,7 @@ public virtual async Task DeleteDefaultConnectionStringAsync(Guid id)
{
var tenant = await TenantRepository.GetAsync(id);
tenant.RemoveDefaultConnectionString();
await LocalEventBus.PublishAsync(new TenantChangedEvent(tenant.Id, tenant.NormalizedName));
await TenantRepository.UpdateAsync(tenant);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,16 @@
using Volo.Abp.DependencyInjection;
using Volo.Abp.Domain.Entities.Events;
using Volo.Abp.EventBus;
using Volo.Abp.EventBus.Local;
using Volo.Abp.MultiTenancy;

namespace Volo.Abp.TenantManagement;


[LocalEventHandlerOrder(-1)]
public class TenantConfigurationCacheItemInvalidator :
ILocalEventHandler<EntityChangedEventData<Tenant>>,
ILocalEventHandler<EntityDeletedEventData<Tenant>>, ITransientDependency
ILocalEventHandler<TenantChangedEvent>,
ITransientDependency
{
protected IDistributedCache<TenantConfigurationCacheItem> Cache { get; }

Expand All @@ -22,12 +24,17 @@ public TenantConfigurationCacheItemInvalidator(IDistributedCache<TenantConfigura

public virtual async Task HandleEventAsync(EntityChangedEventData<Tenant> eventData)
{
if (eventData is EntityCreatedEventData<Tenant>)
{
return;
}

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)
Expand All @@ -37,6 +44,7 @@ await Cache.RemoveManyAsync(
{
TenantConfigurationCacheItem.CalculateCacheKey(id, null),
TenantConfigurationCacheItem.CalculateCacheKey(null, normalizedName),
TenantConfigurationCacheItem.CalculateCacheKey(id, normalizedName),
});
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,25 @@
using System.Threading.Tasks;
using Volo.Abp.Caching;
using Volo.Abp.Domain.Services;
using Volo.Abp.EventBus.Local;
using Volo.Abp.MultiTenancy;

namespace Volo.Abp.TenantManagement;

public class TenantManager : DomainService, ITenantManager
{
protected ITenantRepository TenantRepository { get; }
protected IDistributedCache<TenantConfigurationCacheItem> Cache { 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;
Cache = cache;
TenantNormalizer = tenantNormalizer;
LocalEventBus = localEventBus;
}

public virtual async Task<Tenant> CreateAsync(string name)
Expand All @@ -36,7 +40,7 @@ public virtual async Task ChangeNameAsync(Tenant tenant, string name)
var normalizedName = TenantNormalizer.NormalizeName(name);

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.SetNormalizedName(normalizedName);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,30 @@
using System.Linq;
using System.Threading.Tasks;
using Shouldly;
using Volo.Abp.Caching;
using Volo.Abp.MultiTenancy;
using Volo.Abp.Uow;
using Xunit;

namespace Volo.Abp.TenantManagement;

public class TenantAppService_Tests : AbpTenantManagementApplicationTestBase
{
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()
{
_tenantAppService = GetRequiredService<ITenantAppService>();
_unitOfWorkManager = GetRequiredService<IUnitOfWorkManager>();
_cache = GetRequiredService<IDistributedCache<TenantConfigurationCacheItem>>();
_tenantStore = GetRequiredService<ITenantStore>();
_tenantRepository = GetRequiredService<ITenantRepository>();
_tenantNormalizer = GetRequiredService<ITenantNormalizer>();
}

[Fact]
Expand Down Expand Up @@ -108,4 +121,46 @@ public async Task DeleteAsync()
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();
}
}

0 comments on commit 81ed527

Please sign in to comment.