58 ILogger<SessionInvalidationTracker>
logger)
63 this.logger =
logger ??
throw new ArgumentNullException(nameof(
logger));
65 trackedSessions =
new ConcurrentDictionary<(string, long), TaskCompletionSource<SessionInvalidationReason>>();
72 (authenticationContext.
SessionId, authenticationContext.
User.Require(x => x.Id)),
75 var (localSessionId, localUserId) = tuple;
76 logger.LogTrace(
"Tracking session ID for user {userId}: {sessionId}", localUserId, localSessionId);
77 var tcs = new TaskCompletionSource<SessionInvalidationReason>();
78 async void SendInvalidationTopic()
82 SessionInvalidationReason invalidationReason;
85 var otherCancellationReason = tcs.Task;
86 var timeTillSessionExpiry = authenticationContext.SessionExpiry - DateTimeOffset.UtcNow;
87 if (timeTillSessionExpiry > TimeSpan.Zero)
89 var delayTask = asyncDelayer.Delay(timeTillSessionExpiry, applicationLifetime.ApplicationStopping).AsTask();
91 await Task.WhenAny(delayTask, otherCancellationReason);
93 if (delayTask.IsCompleted)
97 invalidationReason = otherCancellationReason.IsCompleted
98 ? await otherCancellationReason
99 : SessionInvalidationReason.TokenExpired;
101 logger.LogTrace(
"Invalidating session ID {sessionID}: {reason}", localSessionId, invalidationReason);
103 catch (OperationCanceledException ex)
105 logger.LogTrace(ex,
"Invalidating session ID {sessionID} due to server shutdown", localSessionId);
106 invalidationReason = SessionInvalidationReason.ServerShutdown;
109 var topicName = Subscription.SessionInvalidatedTopic(authenticationContext);
110 await eventSender.SendAsync(topicName, invalidationReason, CancellationToken.None);
111 await eventSender.CompleteAsync(topicName);
115 logger.LogError(ex,
"Error tracking session {sessionId}!", localSessionId);
119 SendInvalidationTopic();