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); }
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); }
public Task <StreamSubscriptionHandle <T> > ResumeAsync( StreamSubscriptionHandle <T> handle, IAsyncBatchObserver <T> batchObserver, StreamSequenceToken token = null) { return(ResumeAsyncImpl(handle, null, batchObserver, token)); }
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; }
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; } }
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; } }
internal Task <StreamSubscriptionHandle <T> > ResumeAsync( StreamSubscriptionHandle <T> handle, IAsyncBatchObserver <T> observer, StreamSequenceToken token) { return(GetConsumerInterface().ResumeAsync(handle, observer, token)); }
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); } }
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); }
public async Task Cleanup() { // Cleanup producers if (producerInterface != null) { var producer = producerInterface as IStreamControl; if (producer != null) { await producer.Cleanup(); } producerInterface = null; } }
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; }
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; }
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); }
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.");
/// <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; }
/// <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);
public Task <StreamSubscriptionHandle <T> > SubscribeAsync(IAsyncBatchObserver <T> observer) { throw new NotImplementedException(); }
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))); }
public Task <StreamSubscriptionHandle <T> > SubscribeAsync(IAsyncBatchObserver <T> batchObserver, StreamSequenceToken token) { return(GetConsumerInterface().SubscribeAsync(batchObserver, token)); }
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);
public Task <StreamSubscriptionHandle <T> > SubscribeAsync(IAsyncBatchObserver <T> batchObserver) { return(SubscribeAsyncImpl(null, batchObserver, null)); }
/// <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);