public StreamConsumerData AddConsumer(GuidId subscriptionId, StreamId streamId, IStreamConsumerExtension streamConsumer, IStreamFilterPredicateWrapper filter)
 {
     var consumerData = new StreamConsumerData(subscriptionId, streamId, streamConsumer, filter);
     queueData.Add(subscriptionId, consumerData);
     lastActivityTime = DateTime.UtcNow;
     return consumerData;
 }
 public StreamConsumerData(GuidId subscriptionId, StreamId streamId, IStreamConsumerExtension streamConsumer, IStreamFilterPredicateWrapper filter)
 {
     SubscriptionId = subscriptionId;
     StreamId = streamId;
     StreamConsumer = streamConsumer;
     Filter = filter;
 }
 public Task RegisterConsumer(GuidId subscriptionId, StreamId streamId, string streamProvider, IStreamConsumerExtension streamConsumer, IStreamFilterPredicateWrapper filter)
 {
     if (!IsImplicitSubscriber(streamConsumer, streamId))
     {
         throw new ArgumentOutOfRangeException(streamId.ToString(), "Only implicit subscriptions are supported.");
     }
     return TaskDone.Done;
 }
 public Task AddSubscriber(GuidId subscriptionId, StreamId streamId, IStreamConsumerExtension streamConsumer,
                           IStreamFilterPredicateWrapper filter)
 {
     return(Task.CompletedTask);
 }
 internal void AddRemoteSubscriber(GuidId subscriptionId, IStreamConsumerExtension streamConsumer, IStreamFilterPredicateWrapper filter)
 {
     consumers.TryAdd(subscriptionId, Tuple.Create(streamConsumer, filter));
 }
        // Called by rendezvous when new remote subscriber subscribes to this stream or when registering a new stream with the pubsub system.
        private void AddSubscriberToSubscriptionCache(
            GuidId subscriptionId,
            StreamId streamId,
            IStreamConsumerExtension streamConsumer,
            IQueueCacheCursor newCursor,
            StreamSequenceToken requestedToken,
            IStreamFilterPredicateWrapper filter)
        {
            StreamConsumerCollection streamDataCollection;
            if (!pubSubCache.TryGetValue(streamId, out streamDataCollection))
            {
                streamDataCollection = new StreamConsumerCollection(DateTime.UtcNow);
                pubSubCache.Add(streamId, streamDataCollection);
            }

            StreamConsumerData data;
            if (!streamDataCollection.TryGetConsumer(subscriptionId, out data))
                data = streamDataCollection.AddConsumer(subscriptionId, streamId, streamConsumer, filter);

            data.LastToken = requestedToken;

            // if we have a new cursor, use it
            if (newCursor != null)
            {
                data.Cursor = newCursor;
            } // else if we don't yet have a cursor, get a cursor at the end of the cash (null sequence token).
            else if (data.Cursor == null && queueCache != null)
            {
                data.Cursor = queueCache.GetCacheCursor(streamId.Guid, streamId.Namespace, null);
            }

            if (data.State == StreamConsumerDataState.Inactive)
                RunConsumerCursor(data, filter).Ignore(); // Start delivering events if not actively doing so
        }
Exemple #7
0
 public OrFilter(IStreamFilterPredicateWrapper filter1, IStreamFilterPredicateWrapper filter2)
 {
     filters = new List<IStreamFilterPredicateWrapper> { filter1, filter2 };
 }
Exemple #8
0
        public StreamSubscriptionHandleImpl(GuidId subscriptionId, IAsyncObserver <T> observer, StreamImpl <T> streamImpl, IStreamFilterPredicateWrapper filterWrapper, StreamSequenceToken token)
        {
            if (subscriptionId == null)
            {
                throw new ArgumentNullException("subscriptionId");
            }
            if (streamImpl == null)
            {
                throw new ArgumentNullException("streamImpl");
            }

            this.subscriptionId = subscriptionId;
            this.observer       = observer;
            this.streamImpl     = streamImpl;
            this.filterWrapper  = filterWrapper;
            expectedToken       = token;
        }
Exemple #9
0
 public Task RegisterConsumer(GuidId subscriptionId, StreamId streamId, string streamProvider, IStreamConsumerExtension streamConsumer, StreamSequenceToken token, IStreamFilterPredicateWrapper filter)
 {
     return IsImplicitSubscriber(streamConsumer, streamId)
         ? TaskDone.Done
         : explicitPubSub.RegisterConsumer(subscriptionId, streamId, streamProvider, streamConsumer, token, filter);
 }
 Task IStreamPubSub.RegisterConsumer(GuidId subscriptionId, StreamId streamId, string streamProvider, IStreamConsumerExtension streamConsumer, IStreamFilterPredicateWrapper filter)
 {
     return(registry.RegisterConsumer(subscriptionId, streamId, streamProvider, streamConsumer, filter));
 }
        // Called by rendezvous when new remote subscriber subscribes to this stream.
        private async Task AddSubscriber_Impl(
            GuidId subscriptionId,
            StreamId streamId,
            IStreamConsumerExtension streamConsumer,
            StreamSequenceToken cacheToken,
            IStreamFilterPredicateWrapper filter)
        {
            if (IsShutdown) return;

            StreamConsumerCollection streamDataCollection;
            if (!pubSubCache.TryGetValue(streamId, out streamDataCollection))
            {
                streamDataCollection = new StreamConsumerCollection(DateTime.UtcNow);
                pubSubCache.Add(streamId, streamDataCollection);
            }

            StreamConsumerData data;
            if (!streamDataCollection.TryGetConsumer(subscriptionId, out data))
                data = streamDataCollection.AddConsumer(subscriptionId, streamId, streamConsumer, filter ?? DefaultStreamFilter);

            if (await DoHandshakeWithConsumer(data, cacheToken))
            {
                if (data.State == StreamConsumerDataState.Inactive)
                    RunConsumerCursor(data, data.Filter).Ignore(); // Start delivering events if not actively doing so
            }
        }
Exemple #12
0
 public StreamConsumerData(StreamId streamId, IStreamConsumerExtension streamConsumer, IStreamFilterPredicateWrapper filter)
 {
     StreamId       = streamId;
     StreamConsumer = streamConsumer;
     Filter         = filter;
 }
Exemple #13
0
        public StreamConsumerData AddConsumer(GuidId subscriptionId, StreamId streamId, IStreamConsumerExtension streamConsumer, IStreamFilterPredicateWrapper filter)
        {
            var consumerData = new StreamConsumerData(subscriptionId, streamId, streamConsumer, filter);

            queueData.Add(subscriptionId, consumerData);
            lastActivityTime = DateTime.UtcNow;
            return(consumerData);
        }
Exemple #14
0
        public Task RegisterConsumer(StreamId streamId, string streamProvider, IStreamConsumerExtension streamConsumer, StreamSequenceToken token, IStreamFilterPredicateWrapper filter)
        {
            var streamRendezvous = GetRendezvousGrain(streamId);

            return(streamRendezvous.RegisterConsumer(streamId, streamConsumer, token, filter));
        }
Exemple #15
0
 public Task RegisterConsumer(StreamId streamId, string streamProvider, IStreamConsumerExtension streamConsumer, StreamSequenceToken token, IStreamFilterPredicateWrapper filter)
 {
     return(IsImplicitSubscriber(streamConsumer, streamId) ? TaskDone.Done :
            explicitPubSub.RegisterConsumer(streamId, streamProvider, streamConsumer, token, filter));
 }
Exemple #16
0
        public async Task RegisterConsumer(
            StreamId streamId,
            IStreamConsumerExtension streamConsumer,
            StreamSequenceToken token,
            IStreamFilterPredicateWrapper filter)
        {
            // This Where clause will return either zero or one PubSubSubscriptionState
            var found = State.Consumers.Where(s => s.Equals(streamId, streamConsumer)).ToArray();
            PubSubSubscriptionState pubSubState;

            if (found.Length == 0)
            {
                pubSubState = new PubSubSubscriptionState(streamId, streamConsumer, token, filter);
                State.Consumers.Add(pubSubState);
            }
            else
            {
                pubSubState = found[0];
                if (filter != null)
                {
                    pubSubState.AddFilter(filter);
                }
            }

            counterConsumersAdded.Increment();
            counterConsumersTotal.Increment();

            LogPubSubCounts("RegisterConsumer {0}", streamConsumer);
            await State.WriteStateAsync();

            int numProducers = State.Producers.Count;

            if (numProducers > 0)
            {
                if (logger.IsVerbose)
                {
                    logger.Info("Notifying {0} existing producer(s) about new consumer {1}. Producers={2}",
                                numProducers, streamConsumer, Utils.EnumerableToString(State.Producers));
                }

                // Notify producers about a new streamConsumer.
                var  tasks                = new List <Task>();
                var  producers            = State.Producers.ToList();
                bool someProducersRemoved = false;

                foreach (var producerState in producers)
                {
                    PubSubPublisherState producer = producerState; // Capture loop variable

                    if (!IsActiveProducer(producer.Producer))
                    {
                        // Producer is not active (could be stopping / shutting down) so skip
                        if (logger.IsVerbose)
                        {
                            logger.Verbose("Producer {0} on stream {1} is not active - skipping.", producer, streamId);
                        }
                        continue;
                    }

                    Task addSubscriberPromise = producer.Producer.AddSubscriber(streamId, streamConsumer, token, filter)
                                                .ContinueWith(t =>
                    {
                        if (t.IsFaulted)
                        {
                            var exc = t.Exception.GetBaseException();
                            if (exc is GrainExtensionNotInstalledException)
                            {
                                logger.Warn((int)ErrorCode.Stream_ProducerIsDead,
                                            "Producer {0} on stream {1} is no longer active - discarding.",
                                            producer, streamId);

                                // This publisher has gone away, so we should cleanup pub-sub state.
                                bool removed         = State.Producers.Remove(producer);
                                someProducersRemoved = true;     // Re-save state changes at end
                                counterProducersRemoved.Increment();
                                counterProducersTotal.DecrementBy(removed ? 1 : 0);

                                // And ignore this error
                            }
                            else
                            {
                                throw exc;
                            }
                        }
                    }, TaskContinuationOptions.OnlyOnFaulted);
                    tasks.Add(addSubscriberPromise);
                }

                Exception exception = null;
                try
                {
                    await Task.WhenAll(tasks);
                }
                catch (Exception exc)
                {
                    exception = exc;
                }

                if (someProducersRemoved)
                {
                    await State.WriteStateAsync();
                }

                if (exception != null)
                {
                    throw exception;
                }
            }
        }
 public Task RegisterConsumer(GuidId subscriptionId, StreamId streamId, string streamProvider, IStreamConsumerExtension streamConsumer, IStreamFilterPredicateWrapper filter)
 {
     return implicitPubSub.IsImplicitSubscriber(streamConsumer, streamId)
         ? implicitPubSub.RegisterConsumer(subscriptionId, streamId, streamProvider, streamConsumer, filter)
         : explicitPubSub.RegisterConsumer(subscriptionId, streamId, streamProvider, streamConsumer, filter);
 }
        public Task RegisterConsumer(GuidId subscriptionId, StreamId streamId, string streamProvider, IStreamConsumerExtension streamConsumer, IStreamFilterPredicateWrapper filter)
        {
            var streamRendezvous = GetRendezvousGrain(streamId);

            return(streamRendezvous.RegisterConsumer(subscriptionId, streamId, streamConsumer, filter));
        }
 public StreamConsumerData AddConsumer(GuidId subscriptionId, StreamId streamId, IStreamConsumerExtension streamConsumer, StreamSequenceToken token, IStreamFilterPredicateWrapper filter)
 {
     var consumerData = new StreamConsumerData(subscriptionId, streamId, streamConsumer, filter);
     queueData.Add(subscriptionId, consumerData);
     return consumerData;
 }
 public Task AddSubscriber(
     GuidId subscriptionId,
     StreamId streamId,
     IStreamConsumerExtension streamConsumer,
     StreamSequenceToken token,
     IStreamFilterPredicateWrapper filter)
 {
     if (logger.IsVerbose) logger.Verbose((int)ErrorCode.PersistentStreamPullingAgent_09, "AddSubscriber: Stream={0} Subscriber={1} Token={2}.", streamId, streamConsumer, token);
     AddSubscriber_Impl(subscriptionId, streamId, streamConsumer, token, filter);
     return TaskDone.Done;
 }
Exemple #21
0
        public async Task <StreamSubscriptionHandle <T> > SubscribeAsync(
            IAsyncObserver <T> observer,
            StreamSequenceToken token,
            StreamFilterPredicate filterFunc = null,
            object filterData = null)
        {
            if (token != null && !IsRewindable)
            {
                throw new ArgumentNullException("token", "Passing a non-null token to a non-rewindable IAsyncObservable.");
            }
            if (observer is GrainReference)
            {
                throw new ArgumentException("On-behalf subscription via grain references is not supported. Only passing of object references is allowed.", "observer");
            }

            if (logger.IsVerbose)
            {
                logger.Verbose("Subscribe Observer={0} Token={1}", observer, token);
            }
            await BindExtensionLazy();

            IStreamFilterPredicateWrapper filterWrapper = null;

            if (filterFunc != null)
            {
                filterWrapper = new FilterPredicateWrapperData(filterData, filterFunc);
            }

            if (logger.IsVerbose)
            {
                logger.Verbose("Subscribe - Connecting to Rendezvous {0} My GrainRef={1} Token={2}",
                               pubSub, myGrainReference, token);
            }

            GuidId subscriptionId = pubSub.CreateSubscriptionId(stream.StreamId, myGrainReference);

            // Optimistic Concurrency:
            // In general, we should first register the subsription with the pubsub (pubSub.RegisterConsumer)
            // and only if it succeeds store it locally (myExtension.SetObserver).
            // Basicaly, those 2 operations should be done as one atomic transaction - either both or none and isolated from concurrent reads.
            // BUT: there is a distributed race here: the first msg may arrive before the call is awaited
            // (since the pubsub notifies the producer that may immideately produce)
            // and will thus not find the subriptionHandle in the extension, basically violating "isolation".
            // Therefore, we employ Optimistic Concurrency Control here to guarantee isolation:
            // we optimisticaly store subscriptionId in the handle first before calling pubSub.RegisterConsumer
            // and undo it in the case of failure.
            // There is no problem with that we call myExtension.SetObserver too early before the handle is registered in pub sub,
            // since this subscriptionId is unique (random Guid) and no one knows it anyway, unless successfully subscribed in the pubsub.
            var subriptionHandle = myExtension.SetObserver(subscriptionId, stream, observer, token, filterWrapper);

            try
            {
                await pubSub.RegisterConsumer(subscriptionId, stream.StreamId, streamProviderName, myGrainReference, filterWrapper);

                return(subriptionHandle);
            } catch (Exception)
            {
                // Undo the previous call myExtension.SetObserver.
                myExtension.RemoveObserver(subscriptionId);
                throw;
            }
        }
Exemple #22
0
        private async Task RunConsumerCursor(StreamConsumerData consumerData, IStreamFilterPredicateWrapper filterWrapper)
        {
            try
            {
                // double check in case of interleaving
                if (consumerData.State == StreamConsumerDataState.Active ||
                    consumerData.Cursor == null)
                {
                    return;
                }

                consumerData.State = StreamConsumerDataState.Active;
                while (consumerData.Cursor != null && consumerData.Cursor.MoveNext())
                {
                    IBatchContainer batch = null;
                    Exception       ex;
                    Task            deliveryTask;
                    try
                    {
                        batch = consumerData.Cursor.GetCurrent(out ex);
                    }
                    catch (DataNotAvailableException dataNotAvailable)
                    {
                        ex = dataNotAvailable;
                    }

                    // Apply filtering to this batch, if applicable
                    if (filterWrapper != null && batch != null)
                    {
                        try
                        {
                            // Apply batch filter to this input batch, to see whether we should deliver it to this consumer.
                            if (!batch.ShouldDeliver(
                                    consumerData.StreamId,
                                    filterWrapper.FilterData,
                                    filterWrapper.ShouldReceive))
                            {
                                continue;                               // Skip this batch -- nothing to do
                            }
                        }
                        catch (Exception exc)
                        {
                            var message = string.Format("Ignoring exception while trying to evaluate subscription filter function {0} on stream {1} in PersistentStreamPullingAgentGrain.RunConsumerCursor", filterWrapper, consumerData.StreamId);
                            logger.Warn((int)ErrorCode.PersistentStreamPullingAgent_13, message, exc);
                        }
                    }

                    if (batch != null)
                    {
                        deliveryTask = consumerData.StreamConsumer
                                       .DeliverBatch(consumerData.StreamId, batch.AsImmutable());
                    }
                    else if (ex == null)
                    {
                        deliveryTask = consumerData.StreamConsumer.CompleteStream(consumerData.StreamId);
                    }
                    else
                    {
                        deliveryTask = consumerData.StreamConsumer.ErrorInStream(consumerData.StreamId, ex);
                    }

                    try
                    {
                        numSentMessagesCounter.Increment();
                        await deliveryTask;
                    }
                    catch (Exception exc)
                    {
                        var message = string.Format("Exception while trying to deliver msgs to stream {0} in PersistentStreamPullingAgentGrain.RunConsumerCursor", consumerData.StreamId);
                        logger.Error((int)ErrorCode.PersistentStreamPullingAgent_14, message, exc);
                    }
                }
                consumerData.State = StreamConsumerDataState.Inactive;
            }
            catch (Exception exc)
            {
                // RunConsumerCursor is fired with .Ignore so we should log if anything goes wrong, because there is no one to catch the exception
                logger.Error((int)ErrorCode.PersistentStreamPullingAgent_15, "Ignored RunConsumerCursor Error", exc);
                throw;
            }
        }
 // Called by rendezvous when new remote subscriber subscribes to this stream.
 private async Task AddSubscriber_Impl(
     GuidId subscriptionId,
     StreamId streamId,
     IStreamConsumerExtension streamConsumer,
     StreamSequenceToken token,
     IStreamFilterPredicateWrapper filter)
 {
     IQueueCacheCursor cursor = null;
     // if not cache, then we can't get cursor and there is no reason to ask consumer for token.
     if (queueCache != null)
     {
         try
         {
             StreamSequenceToken consumerToken = await streamConsumer.GetSequenceToken(subscriptionId);
             // Set cursor if not cursor is set, or if subscription provides new token
             consumerToken = consumerToken ?? token;
             if (token != null)
             {
                 cursor = queueCache.GetCacheCursor(streamId.Guid, streamId.Namespace, consumerToken);
             }
         }
         catch (DataNotAvailableException dataNotAvailableException)
         {
             // notify consumer that the data is not available, if we can.
             streamConsumer.ErrorInStream(subscriptionId, dataNotAvailableException).Ignore();
         }
     }
     AddSubscriberToSubscriptionCache(subscriptionId, streamId, streamConsumer, cursor, filter);
 }
Exemple #24
0
        internal StreamSubscriptionHandleImpl <T> SetObserver <T>(GuidId subscriptionId, StreamImpl <T> stream, IAsyncObserver <T> observer, StreamSequenceToken token, IStreamFilterPredicateWrapper filter)
        {
            if (null == stream)
            {
                throw new ArgumentNullException("stream");
            }
            if (null == observer)
            {
                throw new ArgumentNullException("observer");
            }

            try
            {
                if (logger.IsEnabled(LogLevel.Debug))
                {
                    logger.Debug("{0} AddObserver for stream {1}", providerRuntime.ExecutingEntityIdentity(), stream.StreamId);
                }

                // Note: The caller [StreamConsumer] already handles locking for Add/Remove operations, so we don't need to repeat here.
                var handle = new StreamSubscriptionHandleImpl <T>(subscriptionId, observer, stream, filter, token);
                return(allStreamObservers.AddOrUpdate(subscriptionId, handle, (key, old) => handle) as StreamSubscriptionHandleImpl <T>);
            }
            catch (Exception exc)
            {
                logger.Error(ErrorCode.StreamProvider_AddObserverException,
                             $"{providerRuntime.ExecutingEntityIdentity()} StreamConsumerExtension.AddObserver({stream.StreamId}) caugth exception.", exc);
                throw;
            }
        }
        // Called by rendezvous when new remote subscriber subscribes to this stream.
        private void AddSubscriber_Impl(
            GuidId subscriptionId,
            StreamId streamId,
            IStreamConsumerExtension streamConsumer,
            StreamSequenceToken token,
            IStreamFilterPredicateWrapper filter)
        {
            StreamConsumerCollection streamDataCollection;
            if (!pubSubCache.TryGetValue(streamId, out streamDataCollection))
            {
                streamDataCollection = new StreamConsumerCollection();
                pubSubCache.Add(streamId, streamDataCollection);
            }

            StreamConsumerData data;
            if (!streamDataCollection.TryGetConsumer(subscriptionId, out data))
                data = streamDataCollection.AddConsumer(subscriptionId, streamId, streamConsumer, token, filter);
            
            // Set cursor if not cursor is set, or if subscription provides new token
            if ((data.Cursor == null || token != null) && queueCache != null)
                data.Cursor = queueCache.GetCacheCursor(streamId.Guid, streamId.Namespace, token);
            
            if (data.State == StreamConsumerDataState.Inactive)
                RunConsumerCursor(data, filter).Ignore(); // Start delivering events if not actively doing so
        }
Exemple #26
0
 public OrFilter(IStreamFilterPredicateWrapper filter1, IStreamFilterPredicateWrapper filter2)
 {
     filters = new List <IStreamFilterPredicateWrapper> {
         filter1, filter2
     };
 }
 // Called by rendezvous when new remote subscriber subscribes to this stream.
 private async Task AddSubscriber_Impl(
     GuidId subscriptionId,
     StreamId streamId,
     IStreamConsumerExtension streamConsumer,
     StreamSequenceToken token,
     IStreamFilterPredicateWrapper filter)
 {
     IQueueCacheCursor cursor = null;
     StreamSequenceToken requestedToken = null;
     // if not cache, then we can't get cursor and there is no reason to ask consumer for token.
     if (queueCache != null)
     {
         DataNotAvailableException errorOccured = null;
         try
         {
             requestedToken = await streamConsumer.GetSequenceToken(subscriptionId);
             // Set cursor if not cursor is set, or if subscription provides new token
             requestedToken = requestedToken ?? token;
             if (requestedToken != null)
             {
                 cursor = queueCache.GetCacheCursor(streamId.Guid, streamId.Namespace, requestedToken);
             }
         }
         catch (DataNotAvailableException dataNotAvailableException)
         {
             errorOccured = dataNotAvailableException;
         }
         if (errorOccured != null)
         {
             // notify consumer that the data is not available, if we can.
             await OrleansTaskExtentions.ExecuteAndIgnoreException(() => streamConsumer.ErrorInStream(subscriptionId, errorOccured));
         }
     }
     AddSubscriberToSubscriptionCache(subscriptionId, streamId, streamConsumer, cursor, requestedToken, filter);
 }
Exemple #28
0
 public void AddFilter(IStreamFilterPredicateWrapper filter)
 {
     filters.Add(filter);
 }
        private async Task RunConsumerCursor(StreamConsumerData consumerData, IStreamFilterPredicateWrapper filterWrapper)
        {
            try
            {
                // double check in case of interleaving
                if (consumerData.State == StreamConsumerDataState.Active ||
                    consumerData.Cursor == null) return;
                
                consumerData.State = StreamConsumerDataState.Active;
                while (consumerData.Cursor != null && consumerData.Cursor.MoveNext())
                {
                    IBatchContainer batch = null;
                    Exception ex;
                    Task deliveryTask;
                    bool deliveryFailed = false;
                    try
                    {
                        batch = consumerData.Cursor.GetCurrent(out ex);
                    }
                    catch (DataNotAvailableException dataNotAvailable)
                    {
                        ex = dataNotAvailable;
                    }

                    // Apply filtering to this batch, if applicable
                    if (filterWrapper != null && batch != null)
                    {
                        try
                        {
                            // Apply batch filter to this input batch, to see whether we should deliver it to this consumer.
                            if (!batch.ShouldDeliver(
                                consumerData.StreamId,
                                filterWrapper.FilterData,
                                filterWrapper.ShouldReceive)) continue; // Skip this batch -- nothing to do
                        }
                        catch (Exception exc)
                        {
                            var message = string.Format("Ignoring exception while trying to evaluate subscription filter function {0} on stream {1} in PersistentStreamPullingAgentGrain.RunConsumerCursor", filterWrapper, consumerData.StreamId);
                            logger.Warn((int) ErrorCode.PersistentStreamPullingAgent_13, message, exc);
                        }
                    }

                    if (batch != null)
                    {
                        deliveryTask = AsyncExecutorWithRetries.ExecuteWithRetries(i => DeliverBatchToConsumer(consumerData, batch),
                            AsyncExecutorWithRetries.INFINITE_RETRIES, (exception, i) => !(exception is DataNotAvailableException), config.MaxEventDeliveryTime, DefaultBackoffProvider);
                    }
                    else if (ex == null)
                    {
                        deliveryTask = consumerData.StreamConsumer.CompleteStream(consumerData.SubscriptionId);
                    }
                    else
                    {
                        // If data is not avialable, bring cursor current
                        if (ex is DataNotAvailableException)
                        {
                            consumerData.Cursor = queueCache.GetCacheCursor(consumerData.StreamId.Guid,
                                consumerData.StreamId.Namespace, null);
                        }
                        // Notify client of error.
                        deliveryTask = DeliverErrorToConsumer(consumerData, ex, null);
                    }

                    try
                    {
                        numSentMessagesCounter.Increment();
                        await deliveryTask;
                    }
                    catch (Exception exc)
                    {
                        var message = string.Format("Exception while trying to deliver msgs to stream {0} in PersistentStreamPullingAgentGrain.RunConsumerCursor", consumerData.StreamId);
                        logger.Error((int)ErrorCode.PersistentStreamPullingAgent_14, message, exc);
                        deliveryFailed = true;
                    }
                    // if we failed to deliver a batch
                    if (deliveryFailed && batch != null)
                    {
                        // notify consumer of delivery error, if we can.
                        await OrleansTaskExtentions.ExecuteAndIgnoreException(() => DeliverErrorToConsumer(consumerData, new StreamEventDeliveryFailureException(consumerData.StreamId), batch));

                        // record that there was a delivery failure
                        await streamFailureHandler.OnDeliveryFailure(consumerData.SubscriptionId, streamProviderName,
                            consumerData.StreamId, batch.SequenceToken);
                        // if configured to fault on delivery failure and this is not an implicit subscription, fault and remove the subscription
                        if (streamFailureHandler.ShouldFaultSubsriptionOnError && !SubscriptionMarker.IsImplicitSubscription(consumerData.SubscriptionId.Guid))
                        {
                            try
                            {
                                // notify consumer of faulted subscription, if we can.
                                DeliverErrorToConsumer(consumerData, 
                                    new FaultedSubscriptionException(consumerData.SubscriptionId, consumerData.StreamId), batch)
                                    .Ignore();
                                // mark subscription as faulted.
                                await pubSub.FaultSubscription(consumerData.StreamId, consumerData.SubscriptionId);
                            }
                            finally
                            {
                                // remove subscription
                                RemoveSubscriber_Impl(consumerData.SubscriptionId, consumerData.StreamId);
                            }
                            return;
                        }
                    }
                }
                consumerData.State = StreamConsumerDataState.Inactive;
            }
            catch (Exception exc)
            {
                // RunConsumerCursor is fired with .Ignore so we should log if anything goes wrong, because there is no one to catch the exception
                logger.Error((int)ErrorCode.PersistentStreamPullingAgent_15, "Ignored RunConsumerCursor Error", exc);
                throw;
            }
        }
 private async Task NotifyProducerOfNewSubscriber(PubSubPublisherState producer, GuidId subscriptionId, StreamId streamId,
                                                  IStreamConsumerExtension streamConsumer, IStreamFilterPredicateWrapper filter)
 {
     try
     {
         await producer.Producer.AddSubscriber(subscriptionId, streamId, streamConsumer, filter);
     }
     catch (GrainExtensionNotInstalledException)
     {
         RemoveProducer(producer);
     }
     catch (ClientNotAvailableException)
     {
         RemoveProducer(producer);
     }
 }
Exemple #31
0
 public void AddFilter(IStreamFilterPredicateWrapper filter)
 {
     filters.Add(filter);
 }
        // Called by rendezvous when new remote subsriber subscribes to this stream.
        public Task AddSubscriber(GuidId subscriptionId, StreamId streamId, IStreamConsumerExtension streamConsumer, IStreamFilterPredicateWrapper filter)
        {
            if (logger.IsEnabled(LogLevel.Debug))
            {
                logger.Debug("{0} AddSubscriber {1} for stream {2}", providerRuntime.ExecutingEntityIdentity(), streamConsumer, streamId);
            }

            StreamConsumerExtensionCollection consumers;

            if (remoteConsumers.TryGetValue(streamId, out consumers))
            {
                consumers.AddRemoteSubscriber(subscriptionId, streamConsumer, filter);
            }
            else
            {
                // We got an item when we don't think we're the subscriber. This is a normal race condition.
                // We can drop the item on the floor, or pass it to the rendezvous, or log a warning.
            }
            return(Task.CompletedTask);
        }
        // Called by rendezvous when new remote subsriber subscribes to this stream.
        public Task AddSubscriber(GuidId subscriptionId, StreamId streamId, IStreamConsumerExtension streamConsumer, IStreamFilterPredicateWrapper filter)
        {
            if (logger.IsVerbose)
            {
                logger.Verbose("{0} AddSubscriber {1} for stream {2}", providerRuntime.ExecutingEntityIdentity(), streamConsumer, streamId);
            }

            StreamConsumerExtensionCollection consumers;
            if (remoteConsumers.TryGetValue(streamId, out consumers))
            {
                consumers.AddRemoteSubscriber(subscriptionId, streamConsumer, filter);
            }
            else
            {
                // We got an item when we don't think we're the subscriber. This is a normal race condition.
                // We can drop the item on the floor, or pass it to the rendezvous, or log a warning.
            }
            return TaskDone.Done;
        }
 internal void AddRemoteSubscriber(GuidId subscriptionId, IStreamConsumerExtension streamConsumer, IStreamFilterPredicateWrapper filter)
 {
     consumers.TryAdd(subscriptionId, Tuple.Create(streamConsumer, filter));
 }
 Task IStreamPubSub.RegisterConsumer(GuidId subscriptionId, StreamId streamId, string streamProvider, IStreamConsumerExtension streamConsumer, IStreamFilterPredicateWrapper filter)
 {
     return registry.RegisterConsumer(subscriptionId, streamId, streamProvider, streamConsumer, filter);
 }
Exemple #36
0
 public StreamSubscriptionHandleImpl(GuidId subscriptionId, IAsyncObserver <T> observer, IAsyncBatchObserver <T> batchObserver, StreamImpl <T> streamImpl, IStreamFilterPredicateWrapper filterWrapper, StreamSequenceToken token)
 {
     this.subscriptionId = subscriptionId ?? throw new ArgumentNullException("subscriptionId");
     this.observer       = observer;
     this.batchObserver  = batchObserver;
     this.streamImpl     = streamImpl ?? throw new ArgumentNullException("streamImpl");
     this.filterWrapper  = filterWrapper;
     this.isRewindable   = streamImpl.IsRewindable;
     if (IsRewindable)
     {
         expectedToken = StreamHandshakeToken.CreateStartToken(token);
     }
 }
 public Task RegisterConsumer(GuidId subscriptionId, StreamId streamId, string streamProvider, IStreamConsumerExtension streamConsumer, IStreamFilterPredicateWrapper filter)
 {
     var streamRendezvous = GetRendezvousGrain(streamId);
     return streamRendezvous.RegisterConsumer(subscriptionId, streamId, streamConsumer, filter);
 }
Exemple #38
0
        private async Task RunConsumerCursor(StreamConsumerData consumerData, IStreamFilterPredicateWrapper filterWrapper)
        {
            try
            {
                // double check in case of interleaving
                if (consumerData.State == StreamConsumerDataState.Active ||
                    consumerData.Cursor == null)
                {
                    return;
                }

                consumerData.State = StreamConsumerDataState.Active;
                while (consumerData.Cursor != null)
                {
                    IBatchContainer batch            = null;
                    Exception       exceptionOccured = null;
                    try
                    {
                        batch = GetBatchForConsumer(consumerData.Cursor, filterWrapper, consumerData.StreamId);
                        if (batch == null)
                        {
                            break;
                        }
                    }
                    catch (Exception exc)
                    {
                        exceptionOccured = exc;
                        consumerData.SafeDisposeCursor(logger);
                        consumerData.Cursor = queueCache.GetCacheCursor(consumerData.StreamId, null);
                    }

                    // Apply filtering to this batch, if applicable
                    if (filterWrapper != null && batch != null)
                    {
                        try
                        {
                            // Apply batch filter to this input batch, to see whether we should deliver it to this consumer.
                            if (!batch.ShouldDeliver(
                                    consumerData.StreamId,
                                    filterWrapper.FilterData,
                                    filterWrapper.ShouldReceive))
                            {
                                continue;                               // Skip this batch -- nothing to do
                            }
                        }
                        catch (Exception exc)
                        {
                            var message =
                                $"Ignoring exception while trying to evaluate subscription filter function {filterWrapper} on stream {consumerData.StreamId} in PersistentStreamPullingAgentGrain.RunConsumerCursor";
                            logger.Warn((int)ErrorCode.PersistentStreamPullingAgent_13, message, exc);
                        }
                    }

                    try
                    {
                        numSentMessagesCounter.Increment();
                        if (batch != null)
                        {
                            StreamHandshakeToken newToken = await AsyncExecutorWithRetries.ExecuteWithRetries(
                                i => DeliverBatchToConsumer(consumerData, batch),
                                AsyncExecutorWithRetries.INFINITE_RETRIES,
                                (exception, i) => !(exception is ClientNotAvailableException),
                                this.options.MaxEventDeliveryTime,
                                DeliveryBackoffProvider);

                            if (newToken != null)
                            {
                                consumerData.LastToken = newToken;
                                IQueueCacheCursor newCursor = queueCache.GetCacheCursor(consumerData.StreamId, newToken.Token);
                                consumerData.SafeDisposeCursor(logger);
                                consumerData.Cursor = newCursor;
                            }
                        }
                    }
                    catch (Exception exc)
                    {
                        consumerData.Cursor?.RecordDeliveryFailure();
                        var message =
                            $"Exception while trying to deliver msgs to stream {consumerData.StreamId} in PersistentStreamPullingAgentGrain.RunConsumerCursor";
                        logger.Error(ErrorCode.PersistentStreamPullingAgent_14, message, exc);
                        exceptionOccured = exc is ClientNotAvailableException
                            ? exc
                            : new StreamEventDeliveryFailureException(consumerData.StreamId);
                    }
                    // if we failed to deliver a batch
                    if (exceptionOccured != null)
                    {
                        bool faultedSubscription = await ErrorProtocol(consumerData, exceptionOccured, true, batch, batch?.SequenceToken);

                        if (faultedSubscription)
                        {
                            return;
                        }
                    }
                }
                consumerData.State = StreamConsumerDataState.Inactive;
            }
            catch (Exception exc)
            {
                // RunConsumerCursor is fired with .Ignore so we should log if anything goes wrong, because there is no one to catch the exception
                logger.Error(ErrorCode.PersistentStreamPullingAgent_15, "Ignored RunConsumerCursor Error", exc);
                consumerData.State = StreamConsumerDataState.Inactive;
                throw;
            }
        }
 public Task AddSubscriber(
     GuidId subscriptionId,
     StreamId streamId,
     IStreamConsumerExtension streamConsumer,
     IStreamFilterPredicateWrapper filter)
 {
     if (logger.IsVerbose) logger.Verbose((int)ErrorCode.PersistentStreamPullingAgent_09, "AddSubscriber: Stream={0} Subscriber={1}.", streamId, streamConsumer);
     // cannot await here because explicit consumers trigger this call, so it could cause a deadlock.
     AddSubscriber_Impl(subscriptionId, streamId, streamConsumer, null, filter)
         .LogException(logger, ErrorCode.PersistentStreamPullingAgent_26,
             String.Format("Failed to add subscription for stream {0}." , streamId))
         .Ignore();
     return TaskDone.Done;
 }
Exemple #40
0
 public Task RegisterConsumer(GuidId subscriptionId, StreamId streamId, string streamProvider, IStreamConsumerExtension streamConsumer, IStreamFilterPredicateWrapper filter)
 {
     return(implicitPubSub.IsImplicitSubscriber(streamConsumer, streamId)
         ? implicitPubSub.RegisterConsumer(subscriptionId, streamId, streamProvider, streamConsumer, filter)
         : explicitPubSub.RegisterConsumer(subscriptionId, streamId, streamProvider, streamConsumer, filter));
 }
        private async Task RunConsumerCursor(StreamConsumerData consumerData, IStreamFilterPredicateWrapper filterWrapper)
        {
            try
            {
                // double check in case of interleaving
                if (consumerData.State == StreamConsumerDataState.Active ||
                    consumerData.Cursor == null) return;
                
                consumerData.State = StreamConsumerDataState.Active;
                while (consumerData.Cursor != null)
                {
                    IBatchContainer batch = null;
                    Exception exceptionOccured = null;
                    try
                    {
                        Exception ignore;
                        if (!consumerData.Cursor.MoveNext())
                        {
                            break;
                        }
                        batch = consumerData.Cursor.GetCurrent(out ignore);
                    }
                    catch (Exception exc)
                    {
                        exceptionOccured = exc;
                        consumerData.SafeDisposeCursor(logger);
                        consumerData.Cursor = queueCache.GetCacheCursor(consumerData.StreamId.Guid, consumerData.StreamId.Namespace, null);
                    }

                    // Apply filtering to this batch, if applicable
                    if (filterWrapper != null && batch != null)
                    {
                        try
                        {
                            // Apply batch filter to this input batch, to see whether we should deliver it to this consumer.
                            if (!batch.ShouldDeliver(
                                consumerData.StreamId,
                                filterWrapper.FilterData,
                                filterWrapper.ShouldReceive)) continue; // Skip this batch -- nothing to do
                        }
                        catch (Exception exc)
                        {
                            var message = string.Format("Ignoring exception while trying to evaluate subscription filter function {0} on stream {1} in PersistentStreamPullingAgentGrain.RunConsumerCursor", filterWrapper, consumerData.StreamId);
                            logger.Warn((int) ErrorCode.PersistentStreamPullingAgent_13, message, exc);
                        }
                    }

                    try
                    {
                        numSentMessagesCounter.Increment();
                        if (batch != null)
                        {
                            StreamHandshakeToken newToken = await AsyncExecutorWithRetries.ExecuteWithRetries(
                                i => DeliverBatchToConsumer(consumerData, batch),
                                AsyncExecutorWithRetries.INFINITE_RETRIES,
                                (exception, i) => true,
                                config.MaxEventDeliveryTime,
                                DefaultBackoffProvider);
                            if (newToken != null)
                            {
                                consumerData.LastToken = newToken;
                                IQueueCacheCursor newCursor = queueCache.GetCacheCursor(consumerData.StreamId.Guid,
                                    consumerData.StreamId.Namespace, newToken.Token);
                                consumerData.SafeDisposeCursor(logger);
                                consumerData.Cursor = newCursor;
                            }
                        }
                    }
                    catch (Exception exc)
                    {
                        var message = string.Format("Exception while trying to deliver msgs to stream {0} in PersistentStreamPullingAgentGrain.RunConsumerCursor", consumerData.StreamId);
                        logger.Error((int)ErrorCode.PersistentStreamPullingAgent_14, message, exc);
                        exceptionOccured = new StreamEventDeliveryFailureException(consumerData.StreamId);
                    }
                    // if we failed to deliver a batch
                    if (exceptionOccured != null)
                    {
                        bool faultedSubscription = await ErrorProtocol(consumerData, exceptionOccured, true, batch, batch != null ? batch.SequenceToken : null);
                        if (faultedSubscription) return;
                    }
                }
                consumerData.State = StreamConsumerDataState.Inactive;
            }
            catch (Exception exc)
            {
                // RunConsumerCursor is fired with .Ignore so we should log if anything goes wrong, because there is no one to catch the exception
                logger.Error((int)ErrorCode.PersistentStreamPullingAgent_15, "Ignored RunConsumerCursor Error", exc);
                consumerData.State = StreamConsumerDataState.Inactive;
                throw;
            }
        }
Exemple #42
0
 public Task RegisterConsumer(GuidId subscriptionId, StreamId streamId, string streamProvider, IStreamConsumerExtension streamConsumer, IStreamFilterPredicateWrapper filter)
 {
     if (!IsImplicitSubscriber(streamConsumer, streamId))
     {
         throw new ArgumentOutOfRangeException(streamId.ToString(), "Only implicit subscriptions are supported.");
     }
     return(TaskDone.Done);
 }
Exemple #43
0
        public async Task RegisterConsumer(
            GuidId subscriptionId,
            InternalStreamId streamId,
            IStreamConsumerExtension streamConsumer,
            IStreamFilterPredicateWrapper filter)
        {
            counterConsumersAdded.Increment();
            PubSubSubscriptionState pubSubState = State.Consumers.FirstOrDefault(s => s.Equals(subscriptionId));

            if (pubSubState != null && pubSubState.IsFaulted)
            {
                throw new FaultedSubscriptionException(subscriptionId, streamId);
            }
            try
            {
                if (pubSubState == null)
                {
                    pubSubState = new PubSubSubscriptionState(subscriptionId, streamId, streamConsumer);
                    State.Consumers.Add(pubSubState);
                }

                if (filter != null)
                {
                    pubSubState.AddFilter(filter);
                }

                LogPubSubCounts("RegisterConsumer {0}", streamConsumer);
                await WriteStateAsync();

                counterConsumersTotal.Increment();
            }
            catch (Exception exc)
            {
                logger.Error(ErrorCode.Stream_RegisterConsumerFailed,
                             $"Failed to register a stream consumer.  Stream: {streamId}, SubscriptionId {subscriptionId}, Consumer: {streamConsumer}", exc);
                // Corrupted state, deactivate grain.
                DeactivateOnIdle();
                throw;
            }

            int numProducers = State.Producers.Count;

            if (numProducers <= 0)
            {
                return;
            }

            if (logger.IsEnabled(LogLevel.Debug))
            {
                logger.Debug("Notifying {0} existing producer(s) about new consumer {1}. Producers={2}",
                             numProducers, streamConsumer, Utils.EnumerableToString(State.Producers));
            }

            // Notify producers about a new streamConsumer.
            var tasks                = new List <Task>();
            var producers            = State.Producers.ToList();
            int initialProducerCount = producers.Count;

            try
            {
                foreach (PubSubPublisherState producerState in producers)
                {
                    tasks.Add(ExecuteProducerTask(producerState, producerState.Producer.AddSubscriber(subscriptionId, streamId, streamConsumer, filter)));
                }

                Exception exception = null;
                try
                {
                    await Task.WhenAll(tasks);
                }
                catch (Exception exc)
                {
                    exception = exc;
                }

                // if the number of producers has been changed, resave state.
                if (State.Producers.Count != initialProducerCount)
                {
                    await WriteStateAsync();

                    counterConsumersTotal.DecrementBy(initialProducerCount - State.Producers.Count);
                }

                if (exception != null)
                {
                    throw exception;
                }
            }
            catch (Exception exc)
            {
                logger.Error(ErrorCode.Stream_RegisterConsumerFailed,
                             $"Failed to update producers while register a stream consumer.  Stream: {streamId}, SubscriptionId {subscriptionId}, Consumer: {streamConsumer}", exc);
                // Corrupted state, deactivate grain.
                DeactivateOnIdle();
                throw;
            }
        }
Exemple #44
0
 public StreamConsumerData(GuidId subscriptionId, StreamId streamId, IStreamConsumerExtension streamConsumer, IStreamFilterPredicateWrapper filter)
 {
     SubscriptionId = subscriptionId;
     StreamId       = streamId;
     StreamConsumer = streamConsumer;
     Filter         = filter;
 }