internal bool SameStreamId(StreamId streamId) { return(IsValid && streamImpl.StreamId.Equals(streamId)); }
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); } }
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); }
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); }
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)) { }
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(); } } }
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())); }
/// <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); }
// For compatibility public static IAsyncStream <T> GetStream <T>(this IStreamProvider streamProvider, Guid id, string ns) => streamProvider.GetStream <T>(StreamId.Create(ns, id));
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); } }
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())); }
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; } }
public Task <StreamHandshakeToken> DeliverImmutable(GuidId subscriptionId, StreamId streamId, Immutable <object> item, StreamSequenceToken currentToken, StreamHandshakeToken handshakeToken) { return(DeliverMutable(subscriptionId, streamId, item.Value, currentToken, handshakeToken)); }
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); } }
internal int DiagCountStreamObservers <T>(StreamId streamId) { return(allStreamObservers.Values .OfType <StreamSubscriptionHandleImpl <T> >() .Aggregate(0, (count, o) => count + (o.SameStreamId(streamId) ? 1 : 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); }
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)) { }
public Task <PubSubSubscriptionState[]> DiagGetConsumers(StreamId streamId) { return(Task.FromResult(GetConsumersForStream(streamId))); }
public Task RemoveSubscriber(GuidId subscriptionId, StreamId streamId) { RemoveSubscriber_Impl(subscriptionId, streamId); return(TaskDone.Done); }
private PubSubSubscriptionState[] GetConsumersForStream(StreamId streamId) { return(State.Consumers.Where(c => !c.IsFaulted && c.Stream.Equals(streamId)).ToArray()); }
internal PubSubPublisherState(StreamId streamId, IStreamProducerExtension streamProducer) { Stream = streamId; Producer = streamProducer; }
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); } }