public void OpenSubscription(long id, SubscriptionConnectionOptions options) { if (openSubscriptions.TryAdd(id, options)) { UpdateClientActivityDate(id); return; } SubscriptionConnectionOptions existingOptions; if(openSubscriptions.TryGetValue(id, out existingOptions) == false) throw new SubscriptionDoesNotExistException("Didn't get existing open subscription while it's expected. Subscription id: " + id); if (existingOptions.ConnectionId.Equals(options.ConnectionId, StringComparison.OrdinalIgnoreCase)) { // reopen subscription on already existing connection - might happen after network connection problems the client tries to reopen UpdateClientActivityDate(id); return; } var config = GetSubscriptionConfig(id); if (SystemTime.UtcNow - config.TimeOfLastClientActivity > TimeSpan.FromTicks(existingOptions.ClientAliveNotificationInterval.Ticks * 3)) { // last connected client didn't send at least two 'client-alive' notifications - let the requesting client to open it ReleaseSubscription(id); openSubscriptions.TryAdd(id, options); return; } throw new SubscriptionInUseException("Subscription is already in use. There can be only a single open subscription connection per subscription."); }
public void OpenSubscription(long id, SubscriptionConnectionOptions options) { SizeLimitedConcurrentSet<string> releasedConnections; if (forciblyReleasedSubscriptions.TryGetValue(id, out releasedConnections) && releasedConnections.Contains(options.ConnectionId)) throw new SubscriptionClosedException("Subscription " + id + " was forcibly released. Cannot reopen it."); if (openSubscriptions.TryAdd(id, options)) { UpdateClientActivityDate(id); return; } SubscriptionConnectionOptions existingOptions; if(openSubscriptions.TryGetValue(id, out existingOptions) == false) throw new SubscriptionDoesNotExistException("Didn't get existing open subscription while it's expected. Subscription id: " + id); if (existingOptions.ConnectionId.Equals(options.ConnectionId, StringComparison.OrdinalIgnoreCase)) { // reopen subscription on already existing connection - might happen after network connection problems the client tries to reopen UpdateClientActivityDate(id); return; } var config = GetSubscriptionConfig(id); var now = SystemTime.UtcNow; var timeSinceBatchSent = now - config.TimeOfSendingLastBatch; if (timeSinceBatchSent > existingOptions.BatchOptions.AcknowledgmentTimeout && SystemTime.UtcNow - config.TimeOfLastClientActivity > TimeSpan.FromTicks(existingOptions.ClientAliveNotificationInterval.Ticks * 3)) { // last connected client exceeded ACK timeout and didn't send at least two 'client-alive' notifications - let the requesting client to open it ForceReleaseAndOpenForNewClient(id, options); return; } switch (options.Strategy) { case SubscriptionOpeningStrategy.TakeOver: if (existingOptions.Strategy != SubscriptionOpeningStrategy.ForceAndKeep) { ForceReleaseAndOpenForNewClient(id, options); return; } break; case SubscriptionOpeningStrategy.ForceAndKeep: ForceReleaseAndOpenForNewClient(id, options); return; } throw new SubscriptionInUseException("Subscription is already in use. There can be only a single open subscription connection per subscription."); }
private void ForceReleaseAndOpenForNewClient(long id, SubscriptionConnectionOptions options) { ReleaseSubscription(id); openSubscriptions.TryAdd(id, options); UpdateClientActivityDate(id); }