diff --git a/src/Backend/AutopilotMonitor.Functions/Services/DelegatedAdminService.cs b/src/Backend/AutopilotMonitor.Functions/Services/DelegatedAdminService.cs index c53a68b0..daa7d57c 100644 --- a/src/Backend/AutopilotMonitor.Functions/Services/DelegatedAdminService.cs +++ b/src/Backend/AutopilotMonitor.Functions/Services/DelegatedAdminService.cs @@ -21,7 +21,12 @@ public class DelegatedAdminService private readonly IAdminRepository _adminRepo; private readonly IMemoryCache _cache; private readonly ILogger _logger; - private readonly TimeSpan _cacheDuration = TimeSpan.FromMinutes(5); + // Per-process cache: on scaled-out Flex Consumption, the scope invalidation in UpsertAsync/revoke + // only clears the mutating instance, so other instances serve a stale delegated (MSP) scope until + // expiry. A short TTL caps that cross-instance window so a granted/revoked delegated assignment + // self-heals in seconds. The lookup is a small Table Storage query. Do NOT raise this back to + // minutes "for performance" — it reintroduces the role flip-flop (see TenantAdminsService). + private readonly TimeSpan _cacheDuration = TimeSpan.FromSeconds(30); public DelegatedAdminService( IAdminRepository adminRepo, @@ -36,7 +41,7 @@ public class DelegatedAdminService /// /// Resolves the caller's effective delegated scope: the set of tenants it may access and the role per /// tenant. Only + enabled rows with a recognized role - /// contribute; pending/revoked/disabled/unknown-role rows are ignored (fail-closed). Cached 5 minutes. + /// contribute; pending/revoked/disabled/unknown-role rows are ignored (fail-closed). Cached briefly (see _cacheDuration). /// Returns an empty (never null) scope for a UPN with no effective assignments. /// public virtual async Task GetScopeAsync(string? upn) diff --git a/src/Backend/AutopilotMonitor.Functions/Services/McpUserService.cs b/src/Backend/AutopilotMonitor.Functions/Services/McpUserService.cs index 4c5f5bf6..acc023b6 100644 --- a/src/Backend/AutopilotMonitor.Functions/Services/McpUserService.cs +++ b/src/Backend/AutopilotMonitor.Functions/Services/McpUserService.cs @@ -22,7 +22,12 @@ public class McpUserService private readonly GlobalAdminService _globalAdminService; private readonly DelegatedAdminService _delegatedAdminService; private readonly AdminConfigurationService _adminConfigService; - private readonly TimeSpan _cacheDuration = TimeSpan.FromMinutes(5); + // Per-process cache for the McpUsers whitelist lookup. On scaled-out Flex Consumption an add/remove + // of an McpUsers row only invalidates the mutating instance, so other instances serve a stale + // allow/deny until expiry. A short TTL caps that cross-instance window so an MCP-access grant/revoke + // self-heals in seconds. The lookup is a single Table Storage point-read. Do NOT raise this back to + // minutes "for performance" — it reintroduces the access flip-flop (see TenantAdminsService). + private readonly TimeSpan _cacheDuration = TimeSpan.FromSeconds(30); public McpUserService( IAdminRepository adminRepo,