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

Clear the tenant cache when creating/update/deleting. #18412

Merged
merged 5 commits into from
Dec 30, 2023
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,10 @@ namespace Volo.Abp.AspNetCore.Mvc.Client;

public class AbpAspNetCoreMvcClientCacheOptions
{
public TimeSpan TenantConfigurationCacheAbsoluteExpiration { get; set; }

public TimeSpan ApplicationConfigurationDtoCacheAbsoluteExpiration { get; set; }

public AbpAspNetCoreMvcClientCacheOptions()
{
TenantConfigurationCacheAbsoluteExpiration = TimeSpan.FromMinutes(5);
ApplicationConfigurationDtoCacheAbsoluteExpiration = TimeSpan.FromSeconds(300);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ public override void ConfigureServices(ServiceConfigurationContext context)
{
Configure<AbpAspNetCoreMvcClientCacheOptions>(options =>
{
options.TenantConfigurationCacheAbsoluteExpiration = TimeSpan.FromSeconds(5);
options.ApplicationConfigurationDtoCacheAbsoluteExpiration = TimeSpan.FromSeconds(5);
});
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.Options;
using Pages.Abp.MultiTenancy.ClientProxies;
using Volo.Abp.AspNetCore.Mvc.MultiTenancy;
using Volo.Abp.Caching;
using Volo.Abp.DependencyInjection;
using Volo.Abp.MultiTenancy;
Expand All @@ -16,13 +14,13 @@ public class MvcRemoteTenantStore : ITenantStore, ITransientDependency
{
protected AbpTenantClientProxy TenantAppService { get; }
protected IHttpContextAccessor HttpContextAccessor { get; }
protected IDistributedCache<TenantConfiguration> Cache { get; }
protected IDistributedCache<TenantConfigurationCacheItem> Cache { get; }
protected AbpAspNetCoreMvcClientCacheOptions Options { get; }

public MvcRemoteTenantStore(
AbpTenantClientProxy tenantAppService,
IHttpContextAccessor httpContextAccessor,
IDistributedCache<TenantConfiguration> cache,
IDistributedCache<TenantConfigurationCacheItem> cache,
IOptions<AbpAspNetCoreMvcClientCacheOptions> options)
{
TenantAppService = tenantAppService;
Expand All @@ -33,129 +31,101 @@ public class MvcRemoteTenantStore : ITenantStore, ITransientDependency

public async Task<TenantConfiguration?> FindAsync(string name)
{
var cacheKey = CreateCacheKey(name);
var cacheKey = TenantConfigurationCacheItem.CalculateCacheKey(name);
var httpContext = HttpContextAccessor?.HttpContext;

if (httpContext != null && httpContext.Items[cacheKey] is TenantConfiguration tenantConfiguration)
if (httpContext != null && httpContext.Items[cacheKey] is TenantConfigurationCacheItem tenantConfigurationInHttpContext)
{
return tenantConfiguration;
return tenantConfigurationInHttpContext?.Value;
}

tenantConfiguration = (await Cache.GetOrAddAsync(
cacheKey,
async () => CreateTenantConfiguration(await TenantAppService.FindTenantByNameAsync(name))!,
() => new DistributedCacheEntryOptions
{
AbsoluteExpirationRelativeToNow = Options.TenantConfigurationCacheAbsoluteExpiration
}
))!;
var tenantConfiguration = await Cache.GetAsync(cacheKey);
if (tenantConfiguration == null)
{
await TenantAppService.FindTenantByNameAsync(name);
tenantConfiguration = await Cache.GetAsync(cacheKey);
}

if (httpContext != null)
{
httpContext.Items[cacheKey] = tenantConfiguration;
}

return tenantConfiguration;
return tenantConfiguration?.Value;
}

public async Task<TenantConfiguration?> FindAsync(Guid id)
{
var cacheKey = CreateCacheKey(id);
var cacheKey = TenantConfigurationCacheItem.CalculateCacheKey(id);
var httpContext = HttpContextAccessor?.HttpContext;

if (httpContext != null && httpContext.Items[cacheKey] is TenantConfiguration tenantConfiguration)
if (httpContext != null && httpContext.Items[cacheKey] is TenantConfigurationCacheItem tenantConfigurationInHttpContext)
{
return tenantConfiguration;
return tenantConfigurationInHttpContext?.Value;
}

tenantConfiguration = (await Cache.GetOrAddAsync(
cacheKey,
async () => CreateTenantConfiguration(await TenantAppService.FindTenantByIdAsync(id))!,
() => new DistributedCacheEntryOptions
{
AbsoluteExpirationRelativeToNow = Options.TenantConfigurationCacheAbsoluteExpiration
}
))!;
var tenantConfiguration = await Cache.GetAsync(cacheKey);
if (tenantConfiguration == null)
{
await TenantAppService.FindTenantByIdAsync(id);
tenantConfiguration = await Cache.GetAsync(cacheKey);
}

if (httpContext != null)
{
httpContext.Items[cacheKey] = tenantConfiguration;
}

return tenantConfiguration;
return tenantConfiguration?.Value;
}

public TenantConfiguration Find(string name)
public TenantConfiguration? Find(string name)
{
var cacheKey = CreateCacheKey(name);
var cacheKey = TenantConfigurationCacheItem.CalculateCacheKey(name);
var httpContext = HttpContextAccessor?.HttpContext;

if (httpContext != null && httpContext.Items[cacheKey] is TenantConfiguration tenantConfiguration)
if (httpContext != null && httpContext.Items[cacheKey] is TenantConfigurationCacheItem tenantConfigurationInHttpContext)
{
return tenantConfiguration;
return tenantConfigurationInHttpContext?.Value;
}

tenantConfiguration = Cache.GetOrAdd(
cacheKey,
() => AsyncHelper.RunSync(async () => CreateTenantConfiguration(await TenantAppService.FindTenantByNameAsync(name))!),
() => new DistributedCacheEntryOptions
{
AbsoluteExpirationRelativeToNow = Options.TenantConfigurationCacheAbsoluteExpiration
}
)!;
var tenantConfiguration = Cache.Get(cacheKey);
if (tenantConfiguration == null)
{
AsyncHelper.RunSync(async () => await TenantAppService.FindTenantByNameAsync(name));
tenantConfiguration = Cache.Get(cacheKey);
}

if (httpContext != null)
{
httpContext.Items[cacheKey] = tenantConfiguration;
}

return tenantConfiguration;
return tenantConfiguration?.Value;
}

public TenantConfiguration Find(Guid id)
public TenantConfiguration? Find(Guid id)
{
var cacheKey = CreateCacheKey(id);
var cacheKey = TenantConfigurationCacheItem.CalculateCacheKey(id);
var httpContext = HttpContextAccessor?.HttpContext;

if (httpContext != null && httpContext.Items[cacheKey] is TenantConfiguration tenantConfiguration)
if (httpContext != null && httpContext.Items[cacheKey] is TenantConfigurationCacheItem tenantConfigurationInHttpContext)
{
return tenantConfiguration;
return tenantConfigurationInHttpContext?.Value;
}

tenantConfiguration = Cache.GetOrAdd(
cacheKey,
() => AsyncHelper.RunSync(async () => CreateTenantConfiguration(await TenantAppService.FindTenantByIdAsync(id))!),
() => new DistributedCacheEntryOptions
{
AbsoluteExpirationRelativeToNow = Options.TenantConfigurationCacheAbsoluteExpiration
}
)!;

if (httpContext != null)
var tenantConfiguration = Cache.Get(cacheKey);
if (tenantConfiguration == null)
{
httpContext.Items[cacheKey] = tenantConfiguration;
AsyncHelper.RunSync(async () => await TenantAppService.FindTenantByIdAsync(id));
tenantConfiguration = Cache.Get(cacheKey);
}

return tenantConfiguration;
}

protected virtual TenantConfiguration? CreateTenantConfiguration(FindTenantResultDto tenantResultDto)
{
if (!tenantResultDto.Success || tenantResultDto.TenantId == null)
if (httpContext != null)
{
return null;
httpContext.Items[cacheKey] = tenantConfiguration;
}

return new TenantConfiguration(tenantResultDto.TenantId.Value, tenantResultDto.Name!);
}

protected virtual string CreateCacheKey(string tenantName)
{
return $"RemoteTenantStore_Name_{tenantName}";
}

protected virtual string CreateCacheKey(Guid tenantId)
{
return $"RemoteTenantStore_Id_{tenantId:N}";
return tenantConfiguration?.Value;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
using System;

namespace Volo.Abp.MultiTenancy;

[Serializable]
[IgnoreMultiTenancy]
public class TenantConfigurationCacheItem
{
private const string CacheKeyFormat = "i:{0},n:{1}";

public TenantConfiguration? Value { get; set; }

public TenantConfigurationCacheItem()
{

}

public TenantConfigurationCacheItem(TenantConfiguration? value)
{
Value = value;
}

public static string CalculateCacheKey(Guid? id, string? name)
{
if (id == null && name.IsNullOrWhiteSpace())
{
throw new AbpException("Both id and name can't be invalid.");
}
return string.Format(CacheKeyFormat,
id?.ToString() ?? "null",
(name.IsNullOrWhiteSpace() ? "null" : name));
}

public static string CalculateCacheKey(Guid id)
{
return string.Format(CacheKeyFormat, id.ToString(), "null" );
}

public static string CalculateCacheKey(string name)
{
return string.Format(CacheKeyFormat, "null", name);
}
}

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
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.MultiTenancy;

namespace Volo.Abp.TenantManagement;


public class TenantConfigurationCacheItemInvalidator :
ILocalEventHandler<EntityChangedEventData<Tenant>>,
ILocalEventHandler<EntityDeletedEventData<Tenant>>, ITransientDependency
{
protected IDistributedCache<TenantConfigurationCacheItem> Cache { get; }

public TenantConfigurationCacheItemInvalidator(IDistributedCache<TenantConfigurationCacheItem> cache)
{
Cache = cache;
}

public virtual async Task HandleEventAsync(EntityChangedEventData<Tenant> eventData)
{
await ClearCacheAsync(eventData.Entity.Id, eventData.Entity.Name);
}

public virtual async Task HandleEventAsync(EntityDeletedEventData<Tenant> eventData)
{
await ClearCacheAsync(eventData.Entity.Id, eventData.Entity.Name);
}

protected virtual async Task ClearCacheAsync(Guid? id, string name)
{
await Cache.RemoveManyAsync(
new[]
{
TenantConfigurationCacheItem.CalculateCacheKey(id, null),
TenantConfigurationCacheItem.CalculateCacheKey(null, name),
});
}
}
Original file line number Diff line number Diff line change
@@ -1,17 +1,21 @@
using System;
using System.Threading.Tasks;
using Volo.Abp.Caching;
using Volo.Abp.Domain.Services;
using Volo.Abp.MultiTenancy;

namespace Volo.Abp.TenantManagement;

public class TenantManager : DomainService, ITenantManager
{
protected ITenantRepository TenantRepository { get; }
protected IDistributedCache<TenantConfigurationCacheItem> Cache { get; }

public TenantManager(ITenantRepository tenantRepository)
public TenantManager(ITenantRepository tenantRepository,
IDistributedCache<TenantConfigurationCacheItem> cache)
{
TenantRepository = tenantRepository;

Cache = cache;
}

public virtual async Task<Tenant> CreateAsync(string name)
Expand All @@ -28,6 +32,7 @@ public virtual async Task ChangeNameAsync(Tenant tenant, string name)
Check.NotNull(name, nameof(name));

await ValidateNameAsync(name, tenant.Id);
await Cache.RemoveAsync(TenantConfigurationCacheItem.CalculateCacheKey(tenant.Name));
tenant.SetName(name);
}

Expand Down