Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tenant cache problem fixed #19288

Merged
merged 3 commits into from
Mar 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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));
}
ahmetfarukulu marked this conversation as resolved.
Show resolved Hide resolved
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>)
ahmetfarukulu marked this conversation as resolved.
Show resolved Hide resolved
{
return;
}

await ClearCacheAsync(eventData.Entity.Id, eventData.Entity.NormalizedName);
}

public virtual async Task HandleEventAsync(EntityDeletedEventData<Tenant> eventData)
public virtual async Task HandleEventAsync(TenantChangedEvent eventData)
ahmetfarukulu marked this conversation as resolved.
Show resolved Hide resolved
{
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),
ahmetfarukulu marked this conversation as resolved.
Show resolved Hide resolved
});
}
}
}
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();
}
}
Loading