Esempio n. 1
0
        private IReliableSubscription CreateExternalSubscription()
        {
            //
            // NB: Resolve is synchronous and the environment tries its best to make it non-blocking. In case there's blocking, pause times
            //     during checkpointing can get unbounded (which we don't want). We should consider going async here, which bubbles up through
            //     the Start code path (and the subscription visitors), all the way into the recovery and create subscription code paths.
            //     Because Start may also get called when an inner subscription is created in response to receiving an event, it also spreads
            //     async to observer methods. With upcoming support for ValueTask in .NET vNext, we could entertain this idea without
            //     having to worry too much about allocation costs that have prevented us from going down the Task path on the core event
            //     processing code path.
            //
            //     Going async has other benefits as well, including support for async predicates, selectors, etc. provided we can take care
            //     of "replay" of such outgoing calls (we need them to be repeatable for recovery purposes, so we either need to persist
            //     their results or pass in a sequence number so we can ask for a "replay"). In the context of resolution, it can also enable
            //     powerful dynamic binding, e.g. if an event carries a Uri of another stream to subscribe to:
            //
            //       streamsToSubscribeTo.SelectMany(uri => ctx.GetObservable<T>(uri)).Subscribe(o)
            //
            //     Here, the GetObservable<T>(Uri) call is passed a data-dependent Uri (obtained from an event), so we'd have to dynamically
            //     bind (and thus possibly externally resolve) the observable, which requires async in an OnNext context.
            //
            // NB: We've also worked around the synchronous resolver requirement for "anonymous streams" (used for P2P communication between
            //     engines) by encoding the target QE in the URI of such streams (so the resolver can extract the target QE easily).
            //

            if (!_serviceResolver.TryResolveReliable(_edge.ExternalUri, out _externalReactiveService))
            {
                throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "Can't resolve external output '{0}'.", _edge.ExternalUri));
            }

            var extObserver    = _externalReactiveService.GetObserver <T>(_edge.ExternalUri);
            var thisObservable = _parentReactiveService.GetObservable <T>(_edge.InternalUri);

            var subscription = thisObservable.Subscribe(extObserver, _edge.ExternalSubscriptionUri, state: null);

            return(subscription);
        }