public async Task <Subscription <T> > OpenAsync <T>(long id, SubscriptionConnectionOptions options, string database = null) where T : class { if (options == null) { throw new InvalidOperationException("Cannot open a subscription if options are null"); } if (options.BatchOptions == null) { throw new InvalidOperationException("Cannot open a subscription if batch options are null"); } if (options.BatchOptions.MaxSize.HasValue && options.BatchOptions.MaxSize.Value < 16 * 1024) { throw new InvalidOperationException("Max size value of batch options cannot be lower than that 16 KB"); } var commands = database == null ? documentStore.AsyncDatabaseCommands : documentStore.AsyncDatabaseCommands.ForDatabase(database); var open = true; try { await SendOpenSubscriptionRequest(commands, id, options).ConfigureAwait(false); } catch (SubscriptionException subscriptionException) { if (options.Strategy != SubscriptionOpeningStrategy.WaitForFree || (subscriptionException is SubscriptionInUseException) == false) { throw; } open = false; } var subscription = new Subscription <T>(id, database ?? MultiDatabase.GetDatabaseName(documentStore.Url), options, commands, documentStore.Changes(database), documentStore.Conventions, open, () => SendOpenSubscriptionRequest(commands, id, options)); // to ensure that subscription is open try to call it with the same connection id subscriptions.Add(subscription); return(subscription); }
internal Subscription(SubscriptionConnectionOptions options, AsyncServerClient commands, DocumentConvention conventions) { _options = options; if (_options.SubscriptionId == 0) { throw new ArgumentException("SubscriptionConnectionOptions must specify the SubscriptionId, but was set to zero.", nameof(options)); } _commands = commands; _conventions = conventions; if (typeof(T) != typeof(RavenJObject)) { _isStronglyTyped = true; _generateEntityIdOnTheClient = new GenerateEntityIdOnTheClient(conventions, entity => { throw new InvalidOperationException("Shouldn't be generating new ids here"); }); } }
public Subscription <T> Open <T>(SubscriptionConnectionOptions options, string database = null) where T : class { if (options == null) { throw new InvalidOperationException("Cannot open a subscription if options are null"); } // todo: treat the sharded connection case.. AsyncServerClient commands = (AsyncServerClient )(database == null ? documentStore.AsyncDatabaseCommands : documentStore.AsyncDatabaseCommands.ForDatabase(database)); var subscription = new Subscription <T>(options, commands, documentStore.Conventions); // to ensure that subscription is open try to call it with the same connection id subscriptions.Add(subscription); return(subscription); }
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."); }
private void ForceReleaseAndOpenForNewClient(long id, SubscriptionConnectionOptions oldOptions, SubscriptionConnectionOptions newOptions, SubscriptionConfig config, bool allowExistingClientToAcknowledge = false) { if (allowExistingClientToAcknowledge && config.TimeOfLastAcknowledgment < config.TimeOfSendingLastBatch) { // we know that there is active client with unconfirmed batch // allow him to send ack in nearest future if has enough time var now = SystemTime.UtcNow; var timeSinceBatchSent = now - config.TimeOfSendingLastBatch; if (timeSinceBatchSent < oldOptions.BatchOptions.AcknowledgmentTimeout) { var ackMustBeDeliveredBefore = config.TimeOfSendingLastBatch + oldOptions.BatchOptions.AcknowledgmentTimeout; allowedOneTimeAcknowledgements.TryAdd(id, new OneTimeAcknowledgement { ConnectionId = oldOptions.ConnectionId, ValidUntil = ackMustBeDeliveredBefore, AckDelivered = new ManualResetEventSlim(false) }); } } ReleaseSubscription(id); openSubscriptions.TryAdd(id, newOptions); UpdateClientActivityDate(id); }
public Task <Subscription <RavenJObject> > OpenAsync(long id, SubscriptionConnectionOptions options, string database = null) { return(OpenAsync <RavenJObject>(id, options, database)); }
private static async Task SendOpenSubscriptionRequest(IAsyncDatabaseCommands commands, long id, SubscriptionConnectionOptions options) { using (var request = commands.CreateRequest(string.Format("/subscriptions/open?id={0}&connection={1}", id, options.ConnectionId), "POST")) { try { await request.WriteAsync(RavenJObject.FromObject(options)).ConfigureAwait(false); await request.ExecuteRequestAsync().ConfigureAwait(false); } catch (ErrorResponseException e) { SubscriptionException subscriptionException; if (TryGetSubscriptionException(e, out subscriptionException)) { throw subscriptionException; } throw; } } }
private void ForceReleaseAndOpenForNewClient(long id, SubscriptionConnectionOptions options) { ReleaseSubscription(id); openSubscriptions.TryAdd(id, options); UpdateClientActivityDate(id); }
public Subscription <dynamic> Open(SubscriptionConnectionOptions options, string database = null) { return(Open <dynamic>(options, database)); }
public Subscription <T> Open <T>(long id, SubscriptionConnectionOptions options, string database = null) where T : class { return(innerAsync.OpenAsync <T>(id, options, database).ResultUnwrap()); }
public Subscription <RavenJObject> Open(long id, SubscriptionConnectionOptions options, string database = null) { return(innerAsync.OpenAsync(id, options, database).ResultUnwrap()); }
public Subscription <RavenJObject> Open(SubscriptionConnectionOptions options, string database = null) { return(Open <RavenJObject>(options, database)); }
public Subscription <T> Open <T>(long id, SubscriptionConnectionOptions options, string database = null) where T : class { return(AsyncHelpers.RunSync(() => innerAsync.OpenAsync <T>(id, options, database))); }
public Subscription <RavenJObject> Open(long id, SubscriptionConnectionOptions options, string database = null) { return(AsyncHelpers.RunSync(() => innerAsync.OpenAsync(id, options, database))); }
public Subscription <T> Open <T>(SubscriptionConnectionOptions options, string database = null) where T : class { return(innerAsync.Open <T>(options, database)); }