fix:修复部分数据库查询问题
Some checks failed
ci / release-gate (push) Has been cancelled

This commit is contained in:
2026-08-03 14:22:06 +08:00
parent 9f19bea7ee
commit 2c4a0bad6c
8 changed files with 136 additions and 40 deletions

View File

@@ -38,12 +38,13 @@ internal sealed class CurrentAccessContext(
var isValidated = validatedSession is not null &&
validatedSession.UserId == userId &&
validatedSession.TenantId == tenantContext.TenantId;
if (isValidated && cacheOptions.Value.Mode == AuthorizationCacheMode.Active)
return await LoadCachedSnapshotAsync(
if (isValidated)
return await LoadVersionedSnapshotAsync(
userId,
tenantContext.TenantId,
validatedSession!.Realm,
validatedSession.AuthorizationVersion,
cacheOptions.Value.Mode == AuthorizationCacheMode.Active,
cancellationToken);
if (!isValidated)
{
@@ -148,8 +149,13 @@ internal sealed class CurrentAccessContext(
.ToHashSet(StringComparer.Ordinal);
}
private async Task<CurrentAccessSnapshot> LoadCachedSnapshotAsync(
Guid userId, Guid? tenantId, AuthRealm realm, long version, CancellationToken cancellationToken)
private async Task<CurrentAccessSnapshot> LoadVersionedSnapshotAsync(
Guid userId,
Guid? tenantId,
AuthRealm realm,
long version,
bool useDistributedCache,
CancellationToken cancellationToken)
{
var localKey =
$"authorization-snapshot:v1:{realm}:{tenantId?.ToString("N") ?? "platform"}:{userId:N}:{version}";
@@ -161,26 +167,30 @@ internal sealed class CurrentAccessContext(
AuthorizationCacheTelemetry.Read("l1_snapshot", false);
try
if (useDistributedCache)
{
var distributed = await snapshotCache.GetAsync(realm, tenantId, userId, cancellationToken);
if (distributed is not null && distributed.Version == version)
try
{
AuthorizationCacheTelemetry.Read("redis_snapshot", true);
memoryCache.Set(localKey, distributed.Snapshot,
TimeSpan.FromSeconds(cacheOptions.Value.LocalSnapshotSeconds));
return distributed.Snapshot;
var distributed = await snapshotCache.GetAsync(realm, tenantId, userId, cancellationToken);
if (distributed is not null && distributed.Version == version)
{
AuthorizationCacheTelemetry.Read("redis_snapshot", true);
memoryCache.Set(localKey, distributed.Snapshot,
TimeSpan.FromSeconds(cacheOptions.Value.LocalSnapshotSeconds));
return distributed.Snapshot;
}
if (distributed is not null) AuthorizationCacheTelemetry.VersionMismatch();
}
catch (Exception exception) when (exception is not OperationCanceledException)
{
// A confirmed session may safely fall back to the authorization source of truth.
}
if (distributed is not null) AuthorizationCacheTelemetry.VersionMismatch();
}
catch (Exception exception) when (exception is not OperationCanceledException)
{
// A confirmed session may safely fall back to the authorization source of truth.
AuthorizationCacheTelemetry.Read("redis_snapshot", false);
}
AuthorizationCacheTelemetry.Read("redis_snapshot", false);
AuthorizationCacheTelemetry.PostgresFallback();
if (useDistributedCache) AuthorizationCacheTelemetry.PostgresFallback();
var flight = SnapshotFlights.GetOrAdd(localKey, _ => new Lazy<Task<CurrentAccessSnapshot>>(
() => LoadPermissionSnapshotAsync(userId, tenantId, CancellationToken.None),
LazyThreadSafetyMode.ExecutionAndPublication));
@@ -195,14 +205,17 @@ internal sealed class CurrentAccessContext(
}
memoryCache.Set(localKey, snapshot, TimeSpan.FromSeconds(cacheOptions.Value.LocalSnapshotSeconds));
try
if (useDistributedCache)
{
await snapshotCache.SetAsync(realm, tenantId, userId,
new CachedAuthorizationSnapshot(version, snapshot), cancellationToken);
}
catch (Exception exception) when (exception is not OperationCanceledException)
{
// PostgreSQL remains authoritative; a later request can refill Redis.
try
{
await snapshotCache.SetAsync(realm, tenantId, userId,
new CachedAuthorizationSnapshot(version, snapshot), cancellationToken);
}
catch (Exception exception) when (exception is not OperationCanceledException)
{
// PostgreSQL remains authoritative; a later request can refill Redis.
}
}
return snapshot;
@@ -227,11 +240,11 @@ internal sealed class CurrentAccessContext(
var permissions = roleIds.Length == 0
? new HashSet<string>(StringComparer.Ordinal)
: (await (from binding in dbContext.TenantBackendRolePermissions.AsNoTracking()
join permission in dbContext.BackendPermissions.AsNoTracking() on binding.PermissionCode equals
permission.Code
where binding.TenantId == tenantId && roleIds.Contains(binding.RoleId) &&
(permission.Area == BackendPermissionArea.Tenant || permission.Area == BackendPermissionArea.Both)
select binding.PermissionCode).Distinct().ToArrayAsync(cancellationToken))
join permission in dbContext.BackendPermissions.AsNoTracking() on binding.PermissionCode equals
permission.Code
where binding.TenantId == tenantId && roleIds.Contains(binding.RoleId) &&
(permission.Area == BackendPermissionArea.Tenant || permission.Area == BackendPermissionArea.Both)
select binding.PermissionCode).Distinct().ToArrayAsync(cancellationToken))
.ToHashSet(StringComparer.Ordinal);
return new CurrentAccessSnapshot(
userId, tenantId, true, true, permissions, new HashSet<string>(StringComparer.Ordinal),
@@ -249,4 +262,4 @@ internal sealed class CurrentAccessContext(
new HashSet<string>(StringComparer.Ordinal),
CurrentDataScope.Self);
}
}
}