internal bool SameStreamId(StreamId streamId)
 {
     return(IsValid && streamImpl.StreamId.Equals(streamId));
 }
예제 #2
0
        private async Task AsyncTimerCallback(object state)
        {
            try
            {
                var myQueueId = (QueueId)(state);
                if (timer == null)
                {
                    return;                // timer was already removed, last tick
                }
                IQueueAdapterReceiver rcvr = receiver;
                int maxCacheAddCount       = queueCache != null ? queueCache.MaxAddCount : QueueAdapterConstants.UNLIMITED_GET_QUEUE_MSG;

                // loop through the queue until it is empty.
                while (true)
                {
                    if (queueCache != null && queueCache.IsUnderPressure())
                    {
                        // Under back pressure. Exit the loop. Will attempt again in the next timer callback.
                        logger.Info((int)ErrorCode.PersistentStreamPullingAgent_24, String.Format("Stream cache is under pressure. Backing off."));
                        return;
                    }

                    // Retrive one multiBatch from the queue. Every multiBatch has an IEnumerable of IBatchContainers, each IBatchContainer may have multiple events.
                    IList <IBatchContainer> multiBatch = await rcvr.GetQueueMessagesAsync(maxCacheAddCount);

                    if (multiBatch == null || multiBatch.Count == 0)
                    {
                        return;                                              // queue is empty. Exit the loop. Will attempt again in the next timer callback.
                    }
                    if (queueCache != null)
                    {
                        queueCache.AddToCache(multiBatch);
                    }
                    numMessages += multiBatch.Count;
                    numReadMessagesCounter.IncrementBy(multiBatch.Count);
                    if (logger.IsVerbose2)
                    {
                        logger.Verbose2((int)ErrorCode.PersistentStreamPullingAgent_11, "Got {0} messages from queue {1}. So far {2} msgs from this queue.",
                                        multiBatch.Count, myQueueId.ToStringWithHashCode(), numMessages);
                    }

                    foreach (var group in multiBatch.Where(m => m != null)
                             .GroupBy(container => new Tuple <Guid, string>(container.StreamGuid, container.StreamNamespace)))
                    {
                        var streamId = StreamId.GetStreamId(group.Key.Item1, queueAdapter.Name, group.Key.Item2);
                        StreamConsumerCollection streamData;
                        if (pubSubCache.TryGetValue(streamId, out streamData))
                        {
                            StartInactiveCursors(streamId, streamData); // if this is an existing stream, start any inactive cursors
                        }
                        else
                        {
                            RegisterStream(streamId, group.First().SequenceToken).Ignore();
                        };                                                                    // if this is a new stream register as producer of stream in pub sub system
                    }
                }
            }
            catch (Exception exc)
            {
                logger.Error((int)ErrorCode.PersistentStreamPullingAgent_12,
                             String.Format("Exception while PersistentStreamPullingAgentGrain.AsyncTimerCallback"), exc);
            }
        }
예제 #3
0
        private async Task AsyncTimerCallback(object state)
        {
            try
            {
                var myQueueId = (QueueId)(state);
                if (IsShutdown)
                {
                    return;             // timer was already removed, last tick
                }
                IQueueAdapterReceiver rcvr = receiver;
                int maxCacheAddCount       = queueCache != null ? queueCache.MaxAddCount : QueueAdapterConstants.UNLIMITED_GET_QUEUE_MSG;

                // loop through the queue until it is empty.
                while (!IsShutdown) // timer will be set to null when we are asked to shudown.
                {
                    var now = DateTime.UtcNow;
                    // Try to cleanup the pubsub cache at the cadence of 10 times in the configurable StreamInactivityPeriod.
                    if ((now - lastTimeCleanedPubSubCache) >= config.StreamInactivityPeriod.Divide(StreamInactivityCheckFrequency))
                    {
                        lastTimeCleanedPubSubCache = now;
                        CleanupPubSubCache(now);
                    }

                    if (queueCache != null)
                    {
                        IList <IBatchContainer> purgedItems;
                        if (queueCache.TryPurgeFromCache(out purgedItems))
                        {
                            try
                            {
                                await rcvr.MessagesDeliveredAsync(purgedItems);
                            }
                            catch (Exception exc)
                            {
                                logger.Warn((int)ErrorCode.PersistentStreamPullingAgent_27,
                                            String.Format("Exception calling MessagesDeliveredAsync on queue {0}. Ignoring.", myQueueId), exc);
                            }
                        }
                    }

                    if (queueCache != null && queueCache.IsUnderPressure())
                    {
                        // Under back pressure. Exit the loop. Will attempt again in the next timer callback.
                        logger.Info((int)ErrorCode.PersistentStreamPullingAgent_24, "Stream cache is under pressure. Backing off.");
                        return;
                    }

                    // Retrive one multiBatch from the queue. Every multiBatch has an IEnumerable of IBatchContainers, each IBatchContainer may have multiple events.
                    IList <IBatchContainer> multiBatch = await rcvr.GetQueueMessagesAsync(maxCacheAddCount);

                    if (multiBatch == null || multiBatch.Count == 0)
                    {
                        return;                                              // queue is empty. Exit the loop. Will attempt again in the next timer callback.
                    }
                    if (queueCache != null)
                    {
                        queueCache.AddToCache(multiBatch);
                    }
                    numMessages += multiBatch.Count;
                    numReadMessagesCounter.IncrementBy(multiBatch.Count);
                    if (logger.IsVerbose2)
                    {
                        logger.Verbose2((int)ErrorCode.PersistentStreamPullingAgent_11, "Got {0} messages from queue {1}. So far {2} msgs from this queue.",
                                        multiBatch.Count, myQueueId.ToStringWithHashCode(), numMessages);
                    }

                    foreach (var group in
                             multiBatch
                             .Where(m => m != null)
                             .GroupBy(container => new Tuple <Guid, string>(container.StreamGuid, container.StreamNamespace)))
                    {
                        var streamId = StreamId.GetStreamId(group.Key.Item1, queueAdapter.Name, group.Key.Item2);
                        StreamConsumerCollection streamData;
                        if (pubSubCache.TryGetValue(streamId, out streamData))
                        {
                            streamData.RefreshActivity(now);
                            StartInactiveCursors(streamData); // if this is an existing stream, start any inactive cursors
                        }
                        else
                        {
                            RegisterStream(streamId, group.First().SequenceToken, now).Ignore(); // if this is a new stream register as producer of stream in pub sub system
                        }
                    }
                }
            }
            catch (Exception exc)
            {
                logger.Error((int)ErrorCode.PersistentStreamPullingAgent_12, "Exception while PersistentStreamPullingAgentGrain.AsyncTimerCallback", exc);
            }
        }
 public IEnumerable <StreamConsumerData> AllConsumersForStream(StreamId streamId)
 {
     return(queueData.Values.Where(consumer => consumer.StreamId.Equals(streamId)));
 }
        /// <summary>
        /// Read from queue.
        /// Returns true, if data was read, false if it was not
        /// </summary>
        /// <param name="myQueueId"></param>
        /// <param name="rcvr"></param>
        /// <param name="maxCacheAddCount"></param>
        /// <returns></returns>
        private async Task <bool> ReadFromQueue(QueueId myQueueId, IQueueAdapterReceiver rcvr, int maxCacheAddCount)
        {
            if (rcvr == null)
            {
                return(false);
            }

            var now = DateTime.UtcNow;

            // Try to cleanup the pubsub cache at the cadence of 10 times in the configurable StreamInactivityPeriod.
            if ((now - lastTimeCleanedPubSubCache) >= this.options.StreamInactivityPeriod.Divide(StreamInactivityCheckFrequency))
            {
                lastTimeCleanedPubSubCache = now;
                CleanupPubSubCache(now);
            }

            if (queueCache != null)
            {
                IList <IBatchContainer> purgedItems;
                if (queueCache.TryPurgeFromCache(out purgedItems))
                {
                    try
                    {
                        await rcvr.MessagesDeliveredAsync(purgedItems);
                    }
                    catch (Exception exc)
                    {
                        logger.Warn(ErrorCode.PersistentStreamPullingAgent_27,
                                    $"Exception calling MessagesDeliveredAsync on queue {myQueueId}. Ignoring.", exc);
                    }
                }
            }

            if (queueCache != null && queueCache.IsUnderPressure())
            {
                // Under back pressure. Exit the loop. Will attempt again in the next timer callback.
                logger.Info((int)ErrorCode.PersistentStreamPullingAgent_24, "Stream cache is under pressure. Backing off.");
                return(false);
            }

            // Retrieve one multiBatch from the queue. Every multiBatch has an IEnumerable of IBatchContainers, each IBatchContainer may have multiple events.
            IList <IBatchContainer> multiBatch = await rcvr.GetQueueMessagesAsync(maxCacheAddCount);

            if (multiBatch == null || multiBatch.Count == 0)
            {
                return(false);                                             // queue is empty. Exit the loop. Will attempt again in the next timer callback.
            }
            queueCache?.AddToCache(multiBatch);
            numMessages += multiBatch.Count;
            numReadMessagesCounter.IncrementBy(multiBatch.Count);
            if (logger.IsEnabled(LogLevel.Trace))
            {
                logger.Trace(ErrorCode.PersistentStreamPullingAgent_11, "Got {0} messages from queue {1}. So far {2} msgs from this queue.",
                             multiBatch.Count, myQueueId.ToStringWithHashCode(), numMessages);
            }

            foreach (var group in
                     multiBatch
                     .Where(m => m != null)
                     .GroupBy(container => new Tuple <Guid, string>(container.StreamGuid, container.StreamNamespace)))
            {
                var streamId = StreamId.GetStreamId(group.Key.Item1, queueAdapter.Name, group.Key.Item2);
                StreamSequenceToken      startToken = group.First().SequenceToken;
                StreamConsumerCollection streamData;
                if (pubSubCache.TryGetValue(streamId, out streamData))
                {
                    streamData.RefreshActivity(now);
                    StartInactiveCursors(streamData, startToken); // if this is an existing stream, start any inactive cursors
                }
                else
                {
                    RegisterStream(streamId, startToken, now).Ignore(); // if this is a new stream register as producer of stream in pub sub system
                }
            }
            return(true);
        }
예제 #6
0
 public bool ShouldDeliver(StreamId stream, object filterData, StreamFilterPredicate shouldReceiveFunc)
 {
     // ShouldDeliver is called on a per IBatchContainer basis for each IBatchContainer that composes this BatchContainerBatch.
     // Therefore, no filtering is done on the BatchContainerBatch level.
     return(true);
 }
예제 #7
0
        public async Task <StreamHandshakeToken> DeliverMutable(GuidId subscriptionId, StreamId streamId, object item, StreamSequenceToken currentToken, StreamHandshakeToken handshakeToken)
        {
            if (logger.IsVerbose3)
            {
                var itemString = item.ToString();
                itemString = (itemString.Length > MAXIMUM_ITEM_STRING_LOG_LENGTH) ? itemString.Substring(0, MAXIMUM_ITEM_STRING_LOG_LENGTH) + "..." : itemString;
                logger.Verbose3("DeliverItem {0} for subscription {1}", itemString, subscriptionId);
            }
            IStreamSubscriptionHandle observer;

            if (allStreamObservers.TryGetValue(subscriptionId, out observer))
            {
                return(await observer.DeliverItem(item, currentToken, handshakeToken));
            }
            else
            {
                // if no observer attached to the subscription, check if there's onSubscriptinChange actions defined
                ISubscriptionChangeHandler handler;
                if (this.onSubscriptionChangeActionMap.TryGetValue(item.GetType(), out handler))
                {
                    //if the onAddAction attached an observer to the subscription
                    var streamProvider = this.providerRuntime.ServiceProvider
                                         .GetService <IStreamProviderManager>()
                                         .GetStreamProvider(streamId.ProviderName);
                    await handler.InvokeOnAdd(streamId, subscriptionId, isRewindable, streamProvider);

                    if (allStreamObservers.TryGetValue(subscriptionId, out observer))
                    {
                        return(await observer.DeliverItem(item, currentToken, handshakeToken));
                    }
                }
            }

            logger.Warn((int)(ErrorCode.StreamProvider_NoStreamForItem), "{0} got an item for subscription {1}, but I don't have any subscriber for that stream. Dropping on the floor.",
                        providerRuntime.ExecutingEntityIdentity(), subscriptionId);
            // 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 ...
            return(default(StreamHandshakeToken));
        }
 internal StreamEventDeliveryFailureException(StreamId streamId)
     : base(string.Format(ErrorStringFormat, streamId.ProviderName, streamId))
 {
 }
예제 #9
0
        private async Task NotifyProducersOfRemovedSubscription(GuidId subscriptionId, StreamId streamId)
        {
            int numProducersBeforeNotify = State.Producers.Count;

            if (numProducersBeforeNotify > 0)
            {
                if (logger.IsEnabled(LogLevel.Debug))
                {
                    logger.Debug("Notifying {0} existing producers about unregistered consumer.", numProducersBeforeNotify);
                }

                // Notify producers about unregistered consumer.
                List <Task> tasks = State.Producers
                                    .Select(producerState => ExecuteProducerTask(producerState, producerState.Producer.RemoveSubscriber(subscriptionId, streamId)))
                                    .ToList();
                await Task.WhenAll(tasks);

                //if producers got removed
                if (State.Producers.Count < numProducersBeforeNotify)
                {
                    await this.WriteStateAsync();
                }
            }
        }
예제 #10
0
        public async Task <StreamHandshakeToken> DeliverMutable(GuidId subscriptionId, StreamId streamId, object item, StreamSequenceToken currentToken, StreamHandshakeToken handshakeToken)
        {
            if (logger.IsEnabled(LogLevel.Trace))
            {
                var itemString = item.ToString();
                itemString = (itemString.Length > MAXIMUM_ITEM_STRING_LOG_LENGTH) ? itemString.Substring(0, MAXIMUM_ITEM_STRING_LOG_LENGTH) + "..." : itemString;
                logger.Trace("DeliverItem {0} for subscription {1}", itemString, subscriptionId);
            }
            IStreamSubscriptionHandle observer;

            if (allStreamObservers.TryGetValue(subscriptionId, out observer))
            {
                return(await observer.DeliverItem(item, currentToken, handshakeToken));
            }
            else if (this.streamSubscriptionObserver != null)
            {
                var streamProvider = this.providerRuntime.ServiceProvider.GetServiceByName <IStreamProvider>(streamId.ProviderName);
                if (streamProvider != null)
                {
                    var subscriptionHandlerFactory = new StreamSubscriptionHandlerFactory(streamProvider, streamId, streamId.ProviderName, subscriptionId);
                    await this.streamSubscriptionObserver.OnSubscribed(subscriptionHandlerFactory);

                    //check if an observer were attached after handling the new subscription, deliver on it if attached
                    if (allStreamObservers.TryGetValue(subscriptionId, out observer))
                    {
                        return(await observer.DeliverItem(item, currentToken, handshakeToken));
                    }
                }
            }

            logger.Warn((int)(ErrorCode.StreamProvider_NoStreamForItem), "{0} got an item for subscription {1}, but I don't have any subscriber for that stream. Dropping on the floor.",
                        providerRuntime.ExecutingEntityIdentity(), subscriptionId);
            // 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 ...
            return(default(StreamHandshakeToken));
        }
 /// <summary>
 /// Determines whether the specified grain is an implicit subscriber of a given stream.
 /// </summary>
 /// <param name="grainId">The grain identifier.</param>
 /// <param name="streamId">The stream identifier.</param>
 /// <returns>true if the grain id describes an implicit subscriber of the stream described by the stream id.</returns>
 internal bool IsImplicitSubscriber(GrainId grainId, StreamId streamId)
 {
     return(HasImplicitSubscription(streamId.Namespace, grainId.GetTypeCode()));
 }
예제 #12
0
        /// <summary>
        /// Create a reference to a grain that we expect to support the stream consumer extension.
        /// </summary>
        /// <param name="grainFactory">The grain factory used to get consumer references.</param>
        /// <param name="streamId">The stream ID to use for the grain ID construction.</param>
        /// <param name="implTypeCode">The type code of the grain interface.</param>
        /// <returns></returns>
        private IStreamConsumerExtension MakeConsumerReference(IInternalGrainFactory grainFactory, StreamId streamId,
                                                               int implTypeCode)
        {
            var keyExtension = grainsWithKeyExtensions.Contains(implTypeCode)
                ? streamId.Namespace
                : null;
            GrainId grainId = GrainId.GetGrainId(implTypeCode, streamId.Guid, keyExtension);

            return(grainFactory.GetGrain <IStreamConsumerExtension>(grainId));
        }
        private IBatchContainer GetBatchForConsumer(IQueueCacheCursor cursor, IStreamFilterPredicateWrapper filterWrapper, StreamId streamId)
        {
            if (this.options.BatchContainerBatchSize <= 1)
            {
                Exception ignore;

                if (!cursor.MoveNext())
                {
                    return(null);
                }

                return(cursor.GetCurrent(out ignore));
            }
            else if (this.options.BatchContainerBatchSize > 1)
            {
                Exception ignore;
                int       i = 0;
                var       batchContainers = new List <IBatchContainer>();

                while (i < this.options.BatchContainerBatchSize)
                {
                    if (!cursor.MoveNext())
                    {
                        break;
                    }

                    var batchContainer = cursor.GetCurrent(out ignore);
                    if (!batchContainer.ShouldDeliver(
                            streamId,
                            filterWrapper.FilterData,
                            filterWrapper.ShouldReceive))
                    {
                        continue;
                    }

                    batchContainers.Add(batchContainer);
                    i++;
                }

                if (i == 0)
                {
                    return(null);
                }

                return(new BatchContainerBatch(batchContainers));
            }

            return(null);
        }
예제 #14
0
 // For compatibility
 public static IAsyncStream <T> GetStream <T>(this IStreamProvider streamProvider, Guid id, string ns) => streamProvider.GetStream <T>(StreamId.Create(ns, id));
예제 #15
0
        private async Task NotifyProducersOfRemovedSubscription(GuidId subscriptionId, StreamId streamId)
        {
            int numProducers = State.Producers.Count;

            if (numProducers > 0)
            {
                if (logger.IsVerbose)
                {
                    logger.Verbose("Notifying {0} existing producers about unregistered consumer.", numProducers);
                }

                // Notify producers about unregistered consumer.
                List <Task> tasks = State.Producers.Where(producerState => IsActiveProducer(producerState.Producer))
                                    .Select(producerState => producerState.Producer.RemoveSubscriber(subscriptionId, streamId))
                                    .ToList();
                await Task.WhenAll(tasks);
            }
        }
예제 #16
0
 public StreamConsumerData(StreamId streamId, IStreamConsumerExtension streamConsumer, IStreamFilterPredicateWrapper filter)
 {
     StreamId       = streamId;
     StreamConsumer = streamConsumer;
     Filter         = filter;
 }
 public QueueId GetQueueForStream(StreamId streamId)
 {
     return(hashRing.CalculateResponsible((uint)streamId.GetHashCode()));
 }
예제 #18
0
        public async Task RegisterConsumer(
            GuidId subscriptionId,
            StreamId 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.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();
            int initialProducerCount = producers.Count;

            try
            {
                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;
                    }

                    tasks.Add(NotifyProducer(producer, 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;
            }
        }
예제 #19
0
 public Task <StreamHandshakeToken> DeliverImmutable(GuidId subscriptionId, StreamId streamId, Immutable <object> item, StreamSequenceToken currentToken, StreamHandshakeToken handshakeToken)
 {
     return(DeliverMutable(subscriptionId, streamId, item.Value, currentToken, handshakeToken));
 }
예제 #20
0
 private async Task NotifyProducer(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);
     }
 }
예제 #21
0
 internal int DiagCountStreamObservers <T>(StreamId streamId)
 {
     return(allStreamObservers.Values
            .OfType <StreamSubscriptionHandleImpl <T> >()
            .Aggregate(0, (count, o) => count + (o.SameStreamId(streamId) ? 1 : 0)));
 }
예제 #22
0
 public Task <int> ProducerCount(StreamId streamId)
 {
     return(Task.FromResult(State.Producers.Count));
 }
 public Task RemoveSubscriber(GuidId subscriptionId, StreamId streamId)
 {
     RemoveSubscriber_Impl(subscriptionId, streamId);
     return(Task.CompletedTask);
 }
예제 #24
0
 public Task <int> ConsumerCount(StreamId streamId)
 {
     return(Task.FromResult(GetConsumersForStream(streamId).Length));
 }
 internal FaultedSubscriptionException(GuidId subscriptionId, StreamId streamId)
     : base(string.Format(ErrorStringFormat, subscriptionId.Guid, streamId))
 {
 }
예제 #26
0
 public Task <PubSubSubscriptionState[]> DiagGetConsumers(StreamId streamId)
 {
     return(Task.FromResult(GetConsumersForStream(streamId)));
 }
예제 #27
0
 public Task RemoveSubscriber(GuidId subscriptionId, StreamId streamId)
 {
     RemoveSubscriber_Impl(subscriptionId, streamId);
     return(TaskDone.Done);
 }
예제 #28
0
 private PubSubSubscriptionState[] GetConsumersForStream(StreamId streamId)
 {
     return(State.Consumers.Where(c => !c.IsFaulted && c.Stream.Equals(streamId)).ToArray());
 }
예제 #29
0
 internal PubSubPublisherState(StreamId streamId, IStreamProducerExtension streamProducer)
 {
     Stream   = streamId;
     Producer = streamProducer;
 }
예제 #30
0
        private async Task NotifyProducersOfRemovedSubscription(GuidId subscriptionId, StreamId streamId)
        {
            int numProducers = State.Producers.Count;

            if (numProducers > 0)
            {
                if (logger.IsVerbose)
                {
                    logger.Verbose("Notifying {0} existing producers about unregistered consumer.", numProducers);
                }

                // Notify producers about unregistered consumer.
                var tasks = new List <Task>();
                foreach (var producerState in State.Producers.Where(producerState => IsActiveProducer(producerState.Producer)))
                {
                    tasks.Add(producerState.Producer.RemoveSubscriber(subscriptionId, streamId));
                }

                await Task.WhenAll(tasks);
            }
        }