예제 #1
0
        private async Task <StreamSubscriptionHandle <T> > ResumeAsyncImpl(
            StreamSubscriptionHandle <T> handle,
            IAsyncObserver <T> observer,
            IAsyncBatchObserver <T> batchObserver,
            StreamSequenceToken token = null)
        {
            StreamSubscriptionHandleImpl <T> oldHandleImpl = CheckHandleValidity(handle);

            if (token != null && !IsRewindable)
            {
                throw new ArgumentNullException("token", "Passing a non-null token to a non-rewindable IAsyncObservable.");
            }

            if (logger.IsEnabled(LogLevel.Debug))
            {
                logger.Debug("Resume Token={Token}", token);
            }
            await BindExtensionLazy();

            if (logger.IsEnabled(LogLevel.Debug))
            {
                logger.Debug("Resume - Connecting to Rendezvous {0} My GrainRef={1} Token={2}",
                             pubSub, myGrainReference, token);
            }

            StreamSubscriptionHandle <T> newHandle = myExtension.SetObserver(oldHandleImpl.SubscriptionId, stream, observer, batchObserver, token, null);

            // On failure caller should be able to retry using the original handle, so invalidate old handle only if everything succeeded.
            oldHandleImpl.Invalidate();

            return(newHandle);
        }
예제 #2
0
        public Task StopBeingProducer()
        {
            _logger.Info("StopBeingProducer");
            if (!_cleanedUpFlag.TrySet())
            {
                return(TaskDone.Done);
            }

            if (_timers != null)
            {
                foreach (var i in _timers)
                {
                    try
                    {
                        i.Value.Dispose();
                    }
                    catch (Exception exc)
                    {
                        _logger.Error(1, "StopBeingProducer: Timer Dispose() has thrown", exc);
                    }
                }
                _timers = null;
            }
            _observer = null; // Disposing
            return(TaskDone.Done);
        }
예제 #3
0
 public Task <StreamSubscriptionHandle <T> > ResumeAsync(
     StreamSubscriptionHandle <T> handle,
     IAsyncBatchObserver <T> batchObserver,
     StreamSequenceToken token = null)
 {
     return(ResumeAsyncImpl(handle, null, batchObserver, token));
 }
예제 #4
0
        public void BecomeProducer(Guid streamId, IStreamProvider streamProvider, string streamNamespace)
        {
            _cleanedUpFlag.ThrowNotInitializedIfSet();

            _logger.Info("BecomeProducer");
            IAsyncStream <StreamItem> stream = streamProvider.GetStream <StreamItem>(streamId, streamNamespace);

            _observer = stream;
            var observerAsSMSProducer = _observer as SimpleMessageStreamProducer <StreamItem>;

            // only SimpleMessageStreamProducer implements IDisposable and a means to verify it was cleaned up.
            if (null == observerAsSMSProducer)
            {
                _logger.Info("ProducerObserver.BecomeProducer: producer requires no disposal; test short-circuted.");
                _observerDisposedYet = true;
            }
            else
            {
                _logger.Info("ProducerObserver.BecomeProducer: producer performs disposal during finalization.");
                observerAsSMSProducer.OnDisposeTestHook +=
                    () =>
                    _observerDisposedYet = true;
            }
            _streamId        = streamId;
            _streamNamespace = string.IsNullOrWhiteSpace(streamNamespace) ? null : streamNamespace.Trim();
            _providerName    = streamProvider.Name;
        }
예제 #5
0
        private async Task <StreamSubscriptionHandle <T> > SubscribeAsyncImpl(
            IAsyncObserver <T> observer,
            IAsyncBatchObserver <T> batchObserver,
            StreamSequenceToken token,
            string 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.", nameof(observer));
            }
            if (batchObserver is GrainReference)
            {
                throw new ArgumentException("On-behalf subscription via grain references is not supported. Only passing of object references is allowed.", nameof(batchObserver));
            }

            if (logger.IsEnabled(LogLevel.Debug))
            {
                logger.Debug("Subscribe Token={Token}", token);
            }
            await BindExtensionLazy();

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

            GuidId subscriptionId = pubSub.CreateSubscriptionId(stream.InternalStreamId, 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, batchObserver, token, filterData);

            try
            {
                await pubSub.RegisterConsumer(subscriptionId, stream.InternalStreamId, myGrainReference, filterData);

                return(subriptionHandle);
            }
            catch (Exception)
            {
                // Undo the previous call myExtension.SetObserver.
                myExtension.RemoveObserver(subscriptionId);
                throw;
            }
        }
예제 #6
0
        internal StreamSubscriptionHandleImpl <T> SetObserver <T>(
            GuidId subscriptionId,
            StreamImpl <T> stream,
            IAsyncObserver <T> observer,
            IAsyncBatchObserver <T> batchObserver,
            StreamSequenceToken token,
            string filterData)
        {
            if (null == stream)
            {
                throw new ArgumentNullException("stream");
            }

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

                // 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, batchObserver, stream, token, filterData);
                return(allStreamObservers.AddOrUpdate(subscriptionId, handle, (key, old) => handle) as StreamSubscriptionHandleImpl <T>);
            }
            catch (Exception exc)
            {
                logger.Error(ErrorCode.StreamProvider_AddObserverException,
                             $"{providerRuntime.ExecutingEntityIdentity()} StreamConsumerExtension.AddObserver({stream.InternalStreamId}) caugth exception.", exc);
                throw;
            }
        }
예제 #7
0
 internal Task <StreamSubscriptionHandle <T> > ResumeAsync(
     StreamSubscriptionHandle <T> handle,
     IAsyncBatchObserver <T> observer,
     StreamSequenceToken token)
 {
     return(GetConsumerInterface().ResumeAsync(handle, observer, token));
 }
예제 #8
0
        public void RenewProducer(Logger logger, IStreamProvider streamProvider)
        {
            _cleanedUpFlag.ThrowNotInitializedIfSet();

            _logger = logger;
            _logger.Info("RenewProducer");
            IAsyncStream <StreamItem> stream = streamProvider.GetStream <StreamItem>(_streamId, _streamNamespace);

            _observer = stream;
            var observerAsSMSProducer = _observer as SimpleMessageStreamProducer <StreamItem>;

            // only SimpleMessageStreamProducer implements IDisposable and a means to verify it was cleaned up.
            if (null == observerAsSMSProducer)
            {
                //_logger.Info("ProducerObserver.BecomeProducer: producer requires no disposal; test short-circuted.");
                _observerDisposedYet = true;
            }
            else
            {
                //_logger.Info("ProducerObserver.BecomeProducer: producer performs disposal during finalization.");
                observerAsSMSProducer.OnDisposeTestHook +=
                    () =>
                    _observerDisposedYet = true;
            }
        }
 public override Task <StreamSubscriptionHandle <T> > ResumeAsync(IAsyncBatchObserver <T> observer, StreamSequenceToken token = null)
 {
     if (!IsValid)
     {
         throw new InvalidOperationException("Handle is no longer valid. It has been used to unsubscribe or resume.");
     }
     return(this.streamImpl.ResumeAsync(this, observer, token));
 }
 public StreamSubscriptionHandleImpl(GuidId subscriptionId, IAsyncObserver <T> observer, IAsyncBatchObserver <T> batchObserver, StreamImpl <T> streamImpl, StreamSequenceToken token)
 {
     this.subscriptionId = subscriptionId ?? throw new ArgumentNullException("subscriptionId");
     this.observer       = observer;
     this.batchObserver  = batchObserver;
     this.streamImpl     = streamImpl ?? throw new ArgumentNullException("streamImpl");
     this.isRewindable   = streamImpl.IsRewindable;
     if (IsRewindable)
     {
         expectedToken = StreamHandshakeToken.CreateStartToken(token);
     }
 }
예제 #11
0
        public override async Task ObserveResults(IAsyncBatchObserver <TIGrain> observer)
        {
            IIndexInterface        index        = base.IndexFactory.GetIndex(typeof(TIGrain), this._indexName);
            IAsyncStream <TIGrain> resultStream = base.StreamProvider.GetStream <TIGrain>(Guid.NewGuid(), IndexUtils.GetIndexGrainPrimaryKey(typeof(TIGrain), this._indexName));

            IOrleansQueryResultStream <TIGrain> result = new OrleansQueryResultStream <TIGrain>(resultStream);

            //the observer is attached to the query result
            await result.SubscribeAsync(observer);

            //the actual lookup for the query result to be streamed to the observer
            await index.Lookup(result.Cast <IIndexableGrain>(), this._param);
        }
예제 #12
0
        public async Task Cleanup()
        {
            // Cleanup producers
            if (producerInterface != null)
            {
                var producer = producerInterface as IStreamControl;
                if (producer != null)
                {
                    await producer.Cleanup();
                }

                producerInterface = null;
            }
        }
예제 #13
0
        private ProducerObserver(Logger logger, IGrainFactory grainFactory)
        {
            _logger   = logger;
            _observer = null;
            _timers   = new Dictionary <IDisposable, TimerState>();

            _itemsProduced         = 0;
            _expectedItemsProduced = 0;
            _streamId            = default(Guid);
            _providerName        = null;
            _cleanedUpFlag       = new InterlockedFlag();
            _observerDisposedYet = false;
            _grainFactory        = grainFactory;
        }
예제 #14
0
        internal StreamImpl(StreamId streamId, IStreamProviderImpl provider, bool isRewindable)
        {
            if (null == streamId)
            {
                throw new ArgumentNullException("streamId");
            }
            if (null == provider)
            {
                throw new ArgumentNullException("provider");
            }

            this.streamId     = streamId;
            this.provider     = provider;
            producerInterface = null;
            consumerInterface = null;
            initLock          = new object();
            this.isRewindable = isRewindable;
        }
예제 #15
0
        internal IAsyncBatchObserver <T> GetProducerInterface()
        {
            if (producerInterface != null)
            {
                return(producerInterface);
            }

            lock (initLock)
            {
                if (producerInterface != null)
                {
                    return(producerInterface);
                }

                if (provider == null)
                {
                    provider = GetStreamProvider();
                }

                producerInterface = provider.GetProducerInterface <T>(this);
            }
            return(producerInterface);
        }
예제 #16
0
 public Task <StreamSubscriptionHandle <T> > SubscribeAsync(IAsyncBatchObserver <T> observer, StreamSequenceToken token) =>
 throw new NotImplementedException();
 public override Task ObserveResults(IAsyncBatchObserver <TIGrain> observer)
 => throw new NotSupportedException($"Traversing over all the active grains of {typeof(TIGrain)} is not supported.");
예제 #18
0
 /// <summary>
 /// This method queries the active grains for the given grain interface and the filter expression. The filter
 /// expression should contain an indexed field.
 /// </summary>
 /// <typeparam name="TIGrain">the given indexable grain interface type to query over its active instances</typeparam>
 /// <typeparam name="TProperties">the property type to query over</typeparam>
 /// <param name="streamProvider">the stream provider for the query results</param>
 /// <param name="filterExpr">the filter expression of the query</param>
 /// <param name="queryResultObserver">the observer object to be called on every grain found for the query</param>
 /// <returns>the result of the query</returns>
 public Task GetActiveGrains <TIGrain, TProperties>(IStreamProvider streamProvider,
                                                    Expression <Func <TProperties, bool> > filterExpr, IAsyncBatchObserver <TIGrain> queryResultObserver) where TIGrain : IIndexableGrain
 => this.GetActiveGrains <TIGrain, TProperties>(streamProvider).Where(filterExpr).ObserveResults(queryResultObserver);
 public void Invalidate()
 {
     this.streamImpl    = null;
     this.observer      = null;
     this.batchObserver = null;
 }
예제 #20
0
 /// <summary>
 /// Resume batch consumption from a subscription to a stream.
 /// </summary>
 /// <param name="observer">The batcj bserver object.</param>
 /// <param name="token">The stream sequence to be used as an offset to start the subscription from.</param>
 /// <returns>A promise with an updates subscription handle.
 /// </returns>
 public abstract Task <StreamSubscriptionHandle <T> > ResumeAsync(IAsyncBatchObserver <T> observer, StreamSequenceToken token = null);
예제 #21
0
 public Task <StreamSubscriptionHandle <T> > SubscribeAsync(IAsyncBatchObserver <T> observer)
 {
     throw new NotImplementedException();
 }
예제 #22
0
 public Task <StreamSubscriptionHandle <T> > SubscribeAsync(IAsyncBatchObserver <T> batchObserver, StreamSequenceToken token)
 {
     return(SubscribeAsyncImpl(null, batchObserver, token));
 }
 public override Task ObserveResults(IAsyncBatchObserver <TIGrain> observer)
 {
     throw new NotSupportedException(string.Format("Traversing over all the active grains of {0} is not supported.", typeof(TIGrain)));
 }
예제 #24
0
 public Task <StreamSubscriptionHandle <T> > SubscribeAsync(IAsyncBatchObserver <T> batchObserver, StreamSequenceToken token)
 {
     return(GetConsumerInterface().SubscribeAsync(batchObserver, token));
 }
예제 #25
0
 public override Task <StreamSubscriptionHandle <T> > ResumeAsync(IAsyncBatchObserver <T> observer,
                                                                  StreamSequenceToken token = null)
 {
     throw new NotImplementedException();
 }
 public Task <StreamSubscriptionHandle <T> > SubscribeAsync(IAsyncBatchObserver <T> observer, StreamSequenceToken token) => stream.SubscribeAsync(observer, token);
예제 #27
0
 public Task <StreamSubscriptionHandle <T> > SubscribeAsync(IAsyncBatchObserver <T> batchObserver)
 {
     return(SubscribeAsyncImpl(null, batchObserver, null));
 }
예제 #28
0
 /// <summary>
 /// This method queries the active grains for the given
 /// grain interface and the filter expression. The filter
 /// expression should contain an indexed field.
 /// </summary>
 /// <typeparam name="TIGrain">the given grain interface
 /// type to query over its active instances</typeparam>
 /// <param name="gf">the grain factory instance</param>
 /// <param name="streamProvider">the stream provider for the query results</param>
 /// <returns>the query to lookup all active grains of a given type</returns>
 /// <param name="filterExpr">the filter expression of the query</param>
 /// <param name="queryResultObserver">the observer object to be called
 /// on every grain found for the query</param>
 /// <returns>the result of the query</returns>
 public static Task GetActiveGrains <TIGrain, TProperties>(this IGrainFactory gf, IStreamProvider streamProvider, Expression <Func <TProperties, bool> > filterExpr, IAsyncBatchObserver <TIGrain> queryResultObserver) where TIGrain : IIndexableGrain
 {
     return(GrainClient.GrainFactory.GetActiveGrains <TIGrain, TProperties>(streamProvider)
            .Where(filterExpr)
            .ObserveResults(queryResultObserver));
 }
 public Task <StreamSubscriptionHandle <T> > SubscribeAsync(IAsyncBatchObserver <T> observer) => stream.SubscribeAsync(observer);