♻️ Refactor cache system with redis
🐛 Add lock to check in prevent multiple at the same time
This commit is contained in:
@ -1,22 +1,29 @@
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using System.Text.Json;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using NodaTime;
|
||||
using System.Text.Json;
|
||||
using DysonNetwork.Sphere.Storage;
|
||||
|
||||
namespace DysonNetwork.Sphere.Permission;
|
||||
|
||||
public class PermissionService(
|
||||
AppDatabase db,
|
||||
IMemoryCache cache,
|
||||
ICacheService cache,
|
||||
ILogger<PermissionService> logger)
|
||||
{
|
||||
private static readonly TimeSpan CacheExpiration = TimeSpan.FromMinutes(1);
|
||||
|
||||
private const string PermCacheKeyPrefix = "Perm_";
|
||||
private const string PermGroupCacheKeyPrefix = "PermCacheGroup_";
|
||||
private const string PermissionGroupPrefix = "PermGroup_";
|
||||
|
||||
private string GetPermissionCacheKey(string actor, string area, string key) =>
|
||||
$"perm:{actor}:{area}:{key}";
|
||||
private static string _GetPermissionCacheKey(string actor, string area, string key) =>
|
||||
PermCacheKeyPrefix + actor + ":" + area + ":" + key;
|
||||
|
||||
private string GetGroupsCacheKey(string actor) =>
|
||||
$"perm_groups:{actor}";
|
||||
private static string _GetGroupsCacheKey(string actor) =>
|
||||
PermGroupCacheKeyPrefix + actor;
|
||||
|
||||
private static string _GetPermissionGroupKey(string actor) =>
|
||||
PermissionGroupPrefix + actor;
|
||||
|
||||
public async Task<bool> HasPermissionAsync(string actor, string area, string key)
|
||||
{
|
||||
@ -26,26 +33,31 @@ public class PermissionService(
|
||||
|
||||
public async Task<T?> GetPermissionAsync<T>(string actor, string area, string key)
|
||||
{
|
||||
var cacheKey = GetPermissionCacheKey(actor, area, key);
|
||||
var cacheKey = _GetPermissionCacheKey(actor, area, key);
|
||||
|
||||
if (cache.TryGetValue<T>(cacheKey, out var cachedValue))
|
||||
var cachedValue = await cache.GetAsync<T>(cacheKey);
|
||||
if (cachedValue != null)
|
||||
{
|
||||
return cachedValue;
|
||||
}
|
||||
|
||||
var now = SystemClock.Instance.GetCurrentInstant();
|
||||
var groupsKey = GetGroupsCacheKey(actor);
|
||||
var groupsKey = _GetGroupsCacheKey(actor);
|
||||
|
||||
var groupsId = await cache.GetOrCreateAsync(groupsKey, async entry =>
|
||||
var groupsId = await cache.GetAsync<List<Guid>>(groupsKey);
|
||||
if (groupsId == null)
|
||||
{
|
||||
entry.AbsoluteExpirationRelativeToNow = CacheExpiration;
|
||||
return await db.PermissionGroupMembers
|
||||
groupsId = await db.PermissionGroupMembers
|
||||
.Where(n => n.Actor == actor)
|
||||
.Where(n => n.ExpiredAt == null || n.ExpiredAt < now)
|
||||
.Where(n => n.AffectedAt == null || n.AffectedAt >= now)
|
||||
.Select(e => e.GroupId)
|
||||
.ToListAsync();
|
||||
});
|
||||
|
||||
await cache.SetWithGroupsAsync(groupsKey, groupsId,
|
||||
new[] { _GetPermissionGroupKey(actor) },
|
||||
CacheExpiration);
|
||||
}
|
||||
|
||||
var permission = await db.PermissionNodes
|
||||
.Where(n => n.GroupId == null || groupsId.Contains(n.GroupId.Value))
|
||||
@ -56,7 +68,9 @@ public class PermissionService(
|
||||
|
||||
var result = permission is not null ? _DeserializePermissionValue<T>(permission.Value) : default;
|
||||
|
||||
cache.Set(cacheKey, result, CacheExpiration);
|
||||
await cache.SetWithGroupsAsync(cacheKey, result,
|
||||
new[] { _GetPermissionGroupKey(actor) },
|
||||
CacheExpiration);
|
||||
|
||||
return result;
|
||||
}
|
||||
@ -86,7 +100,7 @@ public class PermissionService(
|
||||
await db.SaveChangesAsync();
|
||||
|
||||
// Invalidate related caches
|
||||
InvalidatePermissionCache(actor, area, key);
|
||||
await InvalidatePermissionCacheAsync(actor, area, key);
|
||||
|
||||
return node;
|
||||
}
|
||||
@ -119,8 +133,9 @@ public class PermissionService(
|
||||
await db.SaveChangesAsync();
|
||||
|
||||
// Invalidate related caches
|
||||
InvalidatePermissionCache(actor, area, key);
|
||||
cache.Remove(GetGroupsCacheKey(actor));
|
||||
await InvalidatePermissionCacheAsync(actor, area, key);
|
||||
await cache.RemoveAsync(_GetGroupsCacheKey(actor));
|
||||
await cache.RemoveGroupAsync(_GetPermissionGroupKey(actor));
|
||||
|
||||
return node;
|
||||
}
|
||||
@ -134,7 +149,7 @@ public class PermissionService(
|
||||
await db.SaveChangesAsync();
|
||||
|
||||
// Invalidate cache
|
||||
InvalidatePermissionCache(actor, area, key);
|
||||
await InvalidatePermissionCacheAsync(actor, area, key);
|
||||
}
|
||||
|
||||
public async Task RemovePermissionNodeFromGroup<T>(PermissionGroup group, string actor, string area, string key)
|
||||
@ -148,14 +163,15 @@ public class PermissionService(
|
||||
await db.SaveChangesAsync();
|
||||
|
||||
// Invalidate caches
|
||||
InvalidatePermissionCache(actor, area, key);
|
||||
cache.Remove(GetGroupsCacheKey(actor));
|
||||
await InvalidatePermissionCacheAsync(actor, area, key);
|
||||
await cache.RemoveAsync(_GetGroupsCacheKey(actor));
|
||||
await cache.RemoveGroupAsync(_GetPermissionGroupKey(actor));
|
||||
}
|
||||
|
||||
private void InvalidatePermissionCache(string actor, string area, string key)
|
||||
private async Task InvalidatePermissionCacheAsync(string actor, string area, string key)
|
||||
{
|
||||
var cacheKey = GetPermissionCacheKey(actor, area, key);
|
||||
cache.Remove(cacheKey);
|
||||
var cacheKey = _GetPermissionCacheKey(actor, area, key);
|
||||
await cache.RemoveAsync(cacheKey);
|
||||
}
|
||||
|
||||
private static T? _DeserializePermissionValue<T>(JsonDocument json)
|
||||
|
Reference in New Issue
Block a user