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); }
private static IReliableObserver <T> GetReliableObserver <T>(IReliableReactive c, Uri uri) => c.GetObserver <T>(uri);