You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Session cleanup never deletes anything: NullReferenceException in the tenant filter on every run #1405
SessionCleanupHostedService (Identity) is supposed to delete, once an hour, every UserSession that expired more than 30 days ago. In practice it never deletes anything. On a running API (Production config, PostgreSQL) every hourly run logs Error during session cleanup with:
System.NullReferenceException: Object reference not set to an instance of an object.
at lambda_method2944(Closure, QueryContext)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.ExecuteAsync[TResult](Expression query, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ExecuteDeleteAsync[TSource](IQueryable`1 source, CancellationToken cancellationToken)
at FSH.Modules.Identity.Services.SessionCleanupHostedService.CleanupExpiredSessionsAsync(CancellationToken cancellationToken)
at FSH.Modules.Identity.Services.SessionCleanupHostedService.ExecuteAsync(CancellationToken stoppingToken) in SessionCleanupHostedService.cs:line 40
The service creates a plain DI scope and runs db.UserSessions.Where(s => s.ExpiresAt < cutoff).ExecuteDeleteAsync(). A hosted service has no HTTP request, so Finbuckle never resolves a tenant. UserSession is not an IGlobalEntity, so the default-on tenant isolation in IdentityDbContext puts a tenant query filter on it, and that filter dereferences the (null) current tenant when EF evaluates the query parameters. The loop catches the exception, logs it and tries again an hour later, so the failure is silent apart from the log line, and the UserSessions table grows without bound in every tenant.
Reproduction
Run the API against PostgreSQL with at least one tenant that has a session whose ExpiresAt is more than 30 days in the past.
Wait for the hourly cleanup tick (or invoke SessionCleanupHostedService.CleanupExpiredSessionsAsync directly).
The log shows Error during session cleanup with the NullReferenceException above, and the expired row is still in identity."UserSessions".
Expected
Each run deletes, in every tenant (including tenants with their own connection string), the sessions that expired more than 30 days ago, and keeps sessions that are still valid or expired within the retention window. A failure in one tenant should be logged with that tenant's id without stopping the cleanup of the others.
Activity