Esempio n. 1
0
        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);
        }
Esempio n. 2
0
        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);
        }
Esempio n. 4
0
        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.");
        }
Esempio n. 5
0
        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;
                }
            }
        }
Esempio n. 8
0
 private void ForceReleaseAndOpenForNewClient(long id, SubscriptionConnectionOptions options)
 {
     ReleaseSubscription(id);
     openSubscriptions.TryAdd(id, options);
     UpdateClientActivityDate(id);
 }
Esempio n. 9
0
 public Subscription <dynamic> Open(SubscriptionConnectionOptions options, string database = null)
 {
     return(Open <dynamic>(options, database));
 }
Esempio n. 10
0
 public Subscription <T> Open <T>(long id, SubscriptionConnectionOptions options, string database = null) where T : class
 {
     return(innerAsync.OpenAsync <T>(id, options, database).ResultUnwrap());
 }
Esempio n. 11
0
 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));
 }
Esempio n. 13
0
 public Subscription <T> Open <T>(long id, SubscriptionConnectionOptions options, string database = null) where T : class
 {
     return(AsyncHelpers.RunSync(() => innerAsync.OpenAsync <T>(id, options, database)));
 }
Esempio n. 14
0
 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));
 }