protected virtual async Task DefineOperators(ReactiveClientContext context)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            await context.DefineObservableAsync <IAsyncReactiveQbservable <T>, Expression <Func <T, T, T> >, T>(new Uri(Client.Constants.Observable.Aggregate.Accumulate), (source, accumulate) => source.AsSync().Aggregate(accumulate).AsAsync(), null, CancellationToken.None).ConfigureAwait(false);

            await context.DefineObservableAsync <IAsyncReactiveQbservable <T>, R, Expression <Func <R, T, R> >, R>(new Uri(Client.Constants.Observable.Aggregate.Seed), (source, seed, accumulate) => source.AsSync().Aggregate(seed, accumulate).AsAsync(), null, CancellationToken.None).ConfigureAwait(false);

            await context.DefineObservableAsync <IAsyncReactiveQbservable <T1>, T2, Expression <Func <T2, T1, T2> >, Expression <Func <T2, R> >, R>(new Uri(Client.Constants.Observable.Aggregate.SeedResult), (source, seed, accumulate, selector) => source.AsSync().Aggregate(seed, accumulate, selector).AsAsync(), null, CancellationToken.None).ConfigureAwait(false);

            await context.DefineObservableAsync <IAsyncReactiveQbservable <T>, Expression <Func <T, bool> >, bool>(new Uri(Client.Constants.Observable.All.Predicate), (source, predicate) => source.AsSync().All(predicate).AsAsync(), null, CancellationToken.None).ConfigureAwait(false);

            await context.DefineObservableAsync <IAsyncReactiveQbservable <T>, bool>(new Uri(Client.Constants.Observable.Any.NoArgument), source => source.AsSync().Any().AsAsync(), null, CancellationToken.None).ConfigureAwait(false);

            await context.DefineObservableAsync <IAsyncReactiveQbservable <T>, Expression <Func <T, bool> >, bool>(new Uri(Client.Constants.Observable.Any.Predicate), (source, predicate) => source.AsSync().Any(predicate).AsAsync(), null, CancellationToken.None).ConfigureAwait(false);

            await context.DefineObservableAsync <IAsyncReactiveQbservable <T1>, IAsyncReactiveQbservable <T2>, Expression <Func <T1, T2, R> >, R>(new Uri(Client.Constants.Observable.CombineLatest.ObservableFunc), (source, otherSource, selector) => source.AsSync().CombineLatest(otherSource.AsSync(), selector).AsAsync(), null, CancellationToken.None).ConfigureAwait(false);

            await context.DefineObservableAsync <IAsyncReactiveQbservable <T>, int>(new Uri(Client.Constants.Observable.Count.NoArgument), source => source.AsSync().Count().AsAsync(), null, CancellationToken.None).ConfigureAwait(false);

            await context.DefineObservableAsync <IAsyncReactiveQbservable <T>, Expression <Func <T, bool> >, int>(new Uri(Client.Constants.Observable.Count.Predicate), (source, predicate) => source.AsSync().Count(predicate).AsAsync(), null, CancellationToken.None).ConfigureAwait(false);

            await context.DefineObservableAsync <IAsyncReactiveQbservable <T>, DateTimeOffset, T>(new Uri(Client.Constants.Observable.DelaySubscription.DateTimeOffset), (source, dueTime) => source.AsSync().DelaySubscription(dueTime).AsAsync(), null, CancellationToken.None).ConfigureAwait(false);

            await context.DefineObservableAsync <IAsyncReactiveQbservable <T>, TimeSpan, T>(new Uri(Client.Constants.Observable.DelaySubscription.TimeSpan), (source, dueTime) => source.AsSync().DelaySubscription(dueTime).AsAsync(), null, CancellationToken.None).ConfigureAwait(false);

            await context.DefineObservableAsync <IAsyncReactiveQbservable <T>, DateTimeOffset, T>(new Uri(Client.Constants.Observable.DelaySubscription.V1.DateTimeOffset), (source, dueTime) => ReactiveQbservable.Timer(dueTime).SelectMany(_ => source.AsSync()).AsAsync(), null, CancellationToken.None).ConfigureAwait(false);

            await context.DefineObservableAsync <IAsyncReactiveQbservable <T>, TimeSpan, T>(new Uri(Client.Constants.Observable.DelaySubscription.V1.TimeSpan), (source, dueTime) => ReactiveQbservable.Timer(dueTime).SelectMany(_ => source.AsSync()).AsAsync(), null, CancellationToken.None).ConfigureAwait(false);

            await context.DefineObservableAsync <IAsyncReactiveQbservable <T>, T>(new Uri(Client.Constants.Observable.DistinctUntilChanged.NoArgument), source => source.AsSync().DistinctUntilChanged(DataTypeEqualityComparer <T> .Default).AsAsync(), null, CancellationToken.None).ConfigureAwait(false);

            await context.DefineObservableAsync <IAsyncReactiveQbservable <T>, Expression <Func <T, R> >, T>(new Uri(Client.Constants.Observable.DistinctUntilChanged.Func), (source, keySelector) => source.AsSync().DistinctUntilChanged(keySelector, DataTypeEqualityComparer <R> .Default).AsAsync(), null, CancellationToken.None).ConfigureAwait(false);

            await context.DefineObservableAsync <IAsyncReactiveQbservable <T>, Expression <Action <T> >, T>(new Uri(Client.Constants.Observable.Do.OnNext), (source, onNext) => source.AsSync().Do(onNext).AsAsync(), null, CancellationToken.None).ConfigureAwait(false);

            await context.DefineObservableAsync <IAsyncReactiveQbservable <T>, Expression <Action <T> >, Expression <Action <Exception> >, T>(new Uri(Client.Constants.Observable.Do.OnNextOnError), (source, onNext, onError) => source.AsSync().Do(onNext, onError).AsAsync(), null, CancellationToken.None).ConfigureAwait(false);

            await context.DefineObservableAsync <IAsyncReactiveQbservable <T>, Expression <Action <T> >, Expression <Action>, T>(new Uri(Client.Constants.Observable.Do.OnNextOnCompleted), (source, onNext, onCompleted) => source.AsSync().Do(onNext, onCompleted).AsAsync(), null, CancellationToken.None).ConfigureAwait(false);

            await context.DefineObservableAsync <IAsyncReactiveQbservable <T>, Expression <Action <T> >, Expression <Action <Exception> >, Expression <Action>, T>(new Uri(Client.Constants.Observable.Do.AllActions), (source, onNext, onError, onCompleted) => source.AsSync().Do(onNext, onError, onCompleted).AsAsync(), null, CancellationToken.None).ConfigureAwait(false);

            await context.DefineObservableAsync <IAsyncReactiveQbservable <T>, IAsyncReactiveQbserver <T>, T>(new Uri(Client.Constants.Observable.Do.Observer), (source, observer) => source.AsSync().Do(observer.AsSync()).AsAsync(), null, CancellationToken.None).ConfigureAwait(false);

            await context.DefineObservableAsync <IAsyncReactiveQbservable <T>, Expression <Func <T, R> >, IAsyncReactiveQbserver <R>, T>(new Uri(Client.Constants.Observable.Do.ObserverSelector), (source, selector, observer) => source.AsSync().Do(selector, observer.AsSync()).AsAsync(), null, CancellationToken.None).ConfigureAwait(false);

            await context.DefineObservableAsync <IAsyncReactiveQbservable <T>, Expression <Action>, T>(new Uri(Client.Constants.Observable.Finally.Action), (source, action) => source.AsSync().Finally(action).AsAsync(), null, CancellationToken.None).ConfigureAwait(false);

            await context.DefineObservableAsync <IAsyncReactiveQbservable <T>, T>(new Uri(Client.Constants.Observable.FirstAsync.NoArgument), source => source.AsSync().FirstAsync().AsAsync(), null, CancellationToken.None).ConfigureAwait(false);

            await context.DefineObservableAsync <IAsyncReactiveQbservable <T>, Expression <Func <T, bool> >, T>(new Uri(Client.Constants.Observable.FirstAsync.Func), (source, predicate) => source.AsSync().FirstAsync(predicate).AsAsync(), null, CancellationToken.None).ConfigureAwait(false);

            await context.DefineObservableAsync <IAsyncReactiveQbservable <T>, T>(new Uri(Client.Constants.Observable.FirstOrDefaultAsync.NoArgument), source => source.AsSync().FirstOrDefaultAsync().AsAsync(), null, CancellationToken.None).ConfigureAwait(false);

            await context.DefineObservableAsync <IAsyncReactiveQbservable <T>, Expression <Func <T, bool> >, T>(new Uri(Client.Constants.Observable.FirstOrDefaultAsync.Func), (source, predicate) => source.AsSync().FirstOrDefaultAsync(predicate).AsAsync(), null, CancellationToken.None).ConfigureAwait(false);

            await context.DefineObservableAsync <IAsyncReactiveQbservable <T>, bool>(new Uri(Client.Constants.Observable.IsEmpty.NoArgument), source => source.AsSync().IsEmpty().AsAsync(), null, CancellationToken.None).ConfigureAwait(false);

            await context.DefineObservableAsync <IAsyncReactiveQbservable <T>, long>(new Uri(Client.Constants.Observable.LongCount.NoArgument), source => source.AsSync().LongCount().AsAsync(), null, CancellationToken.None).ConfigureAwait(false);

            await context.DefineObservableAsync <IAsyncReactiveQbservable <T>, Expression <Func <T, bool> >, long>(new Uri(Client.Constants.Observable.LongCount.Predicate), (source, predicate) => source.AsSync().LongCount(predicate).AsAsync(), null, CancellationToken.None).ConfigureAwait(false);

            await context.DefineObservableAsync <IAsyncReactiveQbservable <T>, T>(new Uri(Client.Constants.Observable.Retry.NoArgument), source => source.AsSync().Retry().AsAsync(), null, CancellationToken.None).ConfigureAwait(false);

            await context.DefineObservableAsync <IAsyncReactiveQbservable <T>, int, T>(new Uri(Client.Constants.Observable.Retry.Count), (source, retryCount) => source.AsSync().Retry(retryCount).AsAsync(), null, CancellationToken.None).ConfigureAwait(false);

            await context.DefineObservableAsync <T, T>(new Uri(Client.Constants.Observable.Return.Value), value => ReactiveQbservable.Return(value).AsAsync(), null, CancellationToken.None).ConfigureAwait(false);

            await context.DefineObservableAsync <IAsyncReactiveQbservable <T>, TimeSpan, T>(new Uri(Client.Constants.Observable.Sample.TimeSpan), (source, interval) => source.AsSync().Sample(interval).AsAsync(), null, CancellationToken.None).ConfigureAwait(false);

            await context.DefineObservableAsync <IAsyncReactiveQbservable <T>, IAsyncReactiveQbservable <R>, T>(new Uri(Client.Constants.Observable.Sample.Observable), (source, sampler) => source.AsSync().Sample(sampler.AsSync()).AsAsync(), null, CancellationToken.None).ConfigureAwait(false);

            await context.DefineObservableAsync <IAsyncReactiveQbservable <T>, Expression <Func <T, T, T> >, T>(new Uri(Client.Constants.Observable.Scan.Accumulate), (source, aggregate) => source.AsSync().Scan(aggregate).AsAsync(), null, CancellationToken.None).ConfigureAwait(false);

            await context.DefineObservableAsync <IAsyncReactiveQbservable <T>, R, Expression <Func <R, T, R> >, R>(new Uri(Client.Constants.Observable.Scan.Seed), (source, seed, aggregate) => source.AsSync().Scan(seed, aggregate).AsAsync(), null, CancellationToken.None).ConfigureAwait(false);

            await context.DefineObservableAsync <IAsyncReactiveQbservable <T>, Expression <Func <T, R> >, R>(new Uri(Client.Constants.Observable.Select.Func), (source, selector) => source.AsSync().Select(selector).AsAsync(), null, CancellationToken.None).ConfigureAwait(false);

            await context.DefineObservableAsync <IAsyncReactiveQbservable <T>, Expression <Func <T, int, R> >, R>(new Uri(Client.Constants.Observable.Select.IndexedFunc), (source, selector) => source.AsSync().Select(selector).AsAsync(), null, CancellationToken.None).ConfigureAwait(false);

            await context.DefineObservableAsync <IAsyncReactiveQbservable <T>, IAsyncReactiveQbservable <T>, bool>(new Uri(Client.Constants.Observable.SequenceEqual.NoArgument), (left, right) => left.AsSync().SequenceEqual(right.AsSync()).AsAsync(), null, CancellationToken.None).ConfigureAwait(false);

            await context.DefineObservableAsync <IAsyncReactiveQbservable <T>, int, T>(new Uri(Client.Constants.Observable.Skip.Count), (source, count) => source.AsSync().Skip(count).AsAsync(), null, CancellationToken.None).ConfigureAwait(false);

            await context.DefineObservableAsync <IAsyncReactiveQbservable <T>, TimeSpan, T>(new Uri(Client.Constants.Observable.Skip.TimeSpan), (source, dueTime) => source.AsSync().Skip(dueTime).AsAsync(), null, CancellationToken.None).ConfigureAwait(false);

            await context.DefineObservableAsync <IAsyncReactiveQbservable <T>, DateTimeOffset, T>(new Uri(Client.Constants.Observable.SkipUntil.DateTimeOffset), (source, dueTime) => source.AsSync().SkipUntil(dueTime).AsAsync(), null, CancellationToken.None).ConfigureAwait(false);

            await context.DefineObservableAsync <IAsyncReactiveQbservable <T1>, IAsyncReactiveQbservable <T2>, T1>(new Uri(Client.Constants.Observable.SkipUntil.Observable), (source, triggeringSource) => source.AsSync().SkipUntil(triggeringSource.AsSync()).AsAsync(), null, CancellationToken.None).ConfigureAwait(false);

            await context.DefineObservableAsync <IAsyncReactiveQbservable <T>, Expression <Func <T, bool> >, T>(new Uri(Client.Constants.Observable.SkipWhile.Func), (source, predicate) => source.AsSync().SkipWhile(predicate).AsAsync(), null, CancellationToken.None).ConfigureAwait(false);

            await context.DefineObservableAsync <IAsyncReactiveQbservable <T>, Expression <Func <T, int, bool> >, T>(new Uri(Client.Constants.Observable.SkipWhile.IndexedFunc), (source, predicate) => source.AsSync().SkipWhile(predicate).AsAsync(), null, CancellationToken.None).ConfigureAwait(false);

            await context.DefineObservableAsync <IAsyncReactiveQbservable <T>, T[], T>(new Uri(Client.Constants.Observable.StartWith.Array), (source, values) => source.AsSync().StartWith(values).AsAsync(), null, CancellationToken.None).ConfigureAwait(false);

            await context.DefineObservableAsync <IAsyncReactiveQbservable <T>, int, T>(new Uri(Client.Constants.Observable.Take.Count), (source, count) => source.AsSync().Take(count).AsAsync(), null, CancellationToken.None).ConfigureAwait(false);

            await context.DefineObservableAsync <IAsyncReactiveQbservable <T>, TimeSpan, T>(new Uri(Client.Constants.Observable.Take.TimeSpan), (source, duration) => source.AsSync().Take(duration).AsAsync(), null, CancellationToken.None).ConfigureAwait(false);

            await context.DefineObservableAsync <IAsyncReactiveQbservable <T>, DateTimeOffset, T>(new Uri(Client.Constants.Observable.TakeUntil.DateTimeOffset), (source, startTime) => source.AsSync().TakeUntil(startTime).AsAsync(), null, CancellationToken.None).ConfigureAwait(false);

            await context.DefineObservableAsync <IAsyncReactiveQbservable <T1>, IAsyncReactiveQbservable <T2>, T1>(new Uri(Client.Constants.Observable.TakeUntil.Observable), (source, other) => source.AsSync().TakeUntil(other.AsSync()).AsAsync(), null, CancellationToken.None).ConfigureAwait(false);

            await context.DefineObservableAsync <IAsyncReactiveQbservable <T>, Expression <Func <T, bool> >, T>(new Uri(Client.Constants.Observable.TakeWhile.Func), (source, predicate) => source.AsSync().TakeWhile(predicate).AsAsync(), null, CancellationToken.None).ConfigureAwait(false);

            await context.DefineObservableAsync <IAsyncReactiveQbservable <T>, Expression <Func <T, int, bool> >, T>(new Uri(Client.Constants.Observable.TakeWhile.IndexedFunc), (source, predicate) => source.AsSync().TakeWhile(predicate).AsAsync(), null, CancellationToken.None).ConfigureAwait(false);

            await context.DefineObservableAsync <DateTimeOffset, long>(new Uri(Client.Constants.Observable.Timer.DateTimeOffset), dueTime => ReactiveQbservable.Timer(dueTime).AsAsync(), null, CancellationToken.None).ConfigureAwait(false);

            await context.DefineObservableAsync <DateTimeOffset, TimeSpan, long>(new Uri(Client.Constants.Observable.Timer.DateTimeOffsetTimeSpan), (dueTime, period) => ReactiveQbservable.Timer(dueTime, period).AsAsync(), null, CancellationToken.None).ConfigureAwait(false);

            await context.DefineObservableAsync <TimeSpan, long>(new Uri(Client.Constants.Observable.Timer.TimeSpan), dueTime => ReactiveQbservable.Timer(dueTime).AsAsync(), null, CancellationToken.None).ConfigureAwait(false);

            await context.DefineObservableAsync <TimeSpan, TimeSpan, long>(new Uri(Client.Constants.Observable.Timer.TimeSpanTimeSpan), (dueTime, period) => ReactiveQbservable.Timer(dueTime, period).AsAsync(), null, CancellationToken.None).ConfigureAwait(false);

            await context.DefineObservableAsync <IAsyncReactiveQbservable <T>, IList <T> >(new Uri(Client.Constants.Observable.ToList.NoArgument), source => source.AsSync().ToList().AsAsync(), null, CancellationToken.None).ConfigureAwait(false);

            await context.DefineObservableAsync <IAsyncReactiveQbservable <T>, Expression <Func <T, bool> >, T>(new Uri(Client.Constants.Observable.Where.Func), (source, predicate) => source.AsSync().Where(predicate).AsAsync(), null, CancellationToken.None).ConfigureAwait(false);

            await context.DefineObservableAsync <IAsyncReactiveQbservable <T>, Expression <Func <T, int, bool> >, T>(new Uri(Client.Constants.Observable.Where.IndexedFunc), (source, predicate) => source.AsSync().Where(predicate).AsAsync(), null, CancellationToken.None).ConfigureAwait(false);

            await context.DefineObservableAsync <IAsyncReactiveQbservable <T>, IAsyncReactiveQbservable <T>, T>(new Uri(Client.Constants.Observable.Merge.Binary), (left, right) => left.To <IAsyncReactiveQbservable <T>, IReactiveQbservable <T> >().Merge(right.To <IAsyncReactiveQbservable <T>, IReactiveQbservable <T> >()).AsAsync(), null, CancellationToken.None).ConfigureAwait(false);

            await context.DefineObservableAsync <IAsyncReactiveQbservable <T>[], T>(new Uri(Client.Constants.Observable.Merge.N), sources => ReactiveQbservable.Merge(sources.To <IAsyncReactiveQbservable <T>[], IReactiveQbservable <T>[]>()).AsAsync(), null, CancellationToken.None).ConfigureAwait(false);

            // Non-parameterized defines
            var emptyFactory    = (Expression <Func <IAsyncReactiveQbservable <T> > >)(() => ReactiveQbservable.Empty <T>().AsAsync());
            var emptyObservable = context.Provider.CreateQbservable <T>(emptyFactory.Body);
            await context.DefineObservableAsync <T>(new Uri(Client.Constants.Observable.Empty.NoArgument), emptyObservable, null, CancellationToken.None).ConfigureAwait(false);

            var neverFactory    = (Expression <Func <IAsyncReactiveQbservable <T> > >)(() => ReactiveQbservable.Never <T>().AsAsync());
            var neverObservable = context.Provider.CreateQbservable <T>(neverFactory.Body);
            await context.DefineObservableAsync <T>(new Uri(Client.Constants.Observable.Never.NoArgument), neverObservable, null, CancellationToken.None).ConfigureAwait(false);

            // Higher order defines
            await context.DefineObservableAsync <IAsyncReactiveQbservable <IAsyncReactiveObservable <T> >, T>(new Uri(Client.Constants.Observable.Merge.NoArgument), source => source.To <IAsyncReactiveQbservable <IAsyncReactiveObservable <T> >, IReactiveQbservable <IReactiveObservable <T> > >().Merge().AsAsync(), null, CancellationToken.None).ConfigureAwait(false);

            await context.DefineObservableAsync <IAsyncReactiveQbservable <IAsyncReactiveObservable <T> >, T>(new Uri(Client.Constants.Observable.Switch.NoArgument), source => source.To <IAsyncReactiveQbservable <IAsyncReactiveObservable <T> >, IReactiveQbservable <IReactiveObservable <T> > >().Switch().AsAsync(), null, CancellationToken.None).ConfigureAwait(false);

            await context.DefineObservableAsync <IAsyncReactiveQbservable <T>, TimeSpan, T>(new Uri(Client.Constants.Observable.Throttle.TimeSpan), (source, dueTime) => source.AsSync().Throttle(_ => ReactiveQbservable.Timer(dueTime)).AsAsync(), null, CancellationToken.None).ConfigureAwait(false);

            await context.DefineObservableAsync <IAsyncReactiveQbservable <T>, Expression <Func <T, IAsyncReactiveQbservable <R> > >, R>(
                new Uri(Client.Constants.Observable.SelectMany.Func),
                (source, selector) => source.AsSync().SelectMany(selector.To <Expression <Func <T, IAsyncReactiveQbservable <R> > >, Expression <Func <T, IReactiveQbservable <R> > > >()).AsAsync(),
                null,
                CancellationToken.None).ConfigureAwait(false);

            await context.DefineObservableAsync <IAsyncReactiveQbservable <T1>, Expression <Func <T1, IAsyncReactiveQbservable <T2> > >, Expression <Func <T1, T2, R> >, R>(
                new Uri(Client.Constants.Observable.SelectMany.FuncFunc),
                (source, collectionSelector, resultSelector) => source.AsSync().SelectMany(collectionSelector.To <Expression <Func <T1, IAsyncReactiveQbservable <T2> > >, Expression <Func <T1, IReactiveQbservable <T2> > > >(), resultSelector).AsAsync(),
                null,
                CancellationToken.None).ConfigureAwait(false);

            await context.DefineObservableAsync <IAsyncReactiveQbservable <T>, TimeSpan, IAsyncReactiveQbservable <T> >(new Uri(Client.Constants.Observable.Window.TimeDuration), (source, duration) => source.AsSync().Window(duration).To <IReactiveQbservable <IReactiveQbservable <T> >, IAsyncReactiveQbservable <IAsyncReactiveQbservable <T> > >(), null, CancellationToken.None).ConfigureAwait(false);

            await context.DefineObservableAsync <IAsyncReactiveQbservable <T>, TimeSpan, TimeSpan, IAsyncReactiveQbservable <T> >(new Uri(Client.Constants.Observable.Window.TimeDurationShift), (source, duration, shift) => source.AsSync().Window(duration, shift).To <IReactiveQbservable <IReactiveQbservable <T> >, IAsyncReactiveQbservable <IAsyncReactiveQbservable <T> > >(), null, CancellationToken.None).ConfigureAwait(false);

            await context.DefineObservableAsync <IAsyncReactiveQbservable <T>, int, IAsyncReactiveQbservable <T> >(new Uri(Client.Constants.Observable.Window.Count), (source, count) => source.AsSync().Window(count).To <IReactiveQbservable <IReactiveQbservable <T> >, IAsyncReactiveQbservable <IAsyncReactiveQbservable <T> > >(), null, CancellationToken.None).ConfigureAwait(false);

            await context.DefineObservableAsync <IAsyncReactiveQbservable <T>, int, int, IAsyncReactiveQbservable <T> >(new Uri(Client.Constants.Observable.Window.CountSkip), (source, count, skip) => source.AsSync().Window(count, skip).To <IReactiveQbservable <IReactiveQbservable <T> >, IAsyncReactiveQbservable <IAsyncReactiveQbservable <T> > >(), null, CancellationToken.None).ConfigureAwait(false);

            await context.DefineObservableAsync <IAsyncReactiveQbservable <T>, TimeSpan, int, IAsyncReactiveQbservable <T> >(new Uri(Client.Constants.Observable.Window.TimeCount), (source, duration, count) => source.AsSync().Window(duration, count).To <IReactiveQbservable <IReactiveQbservable <T> >, IAsyncReactiveQbservable <IAsyncReactiveQbservable <T> > >(), null, CancellationToken.None).ConfigureAwait(false);

            await context.DefineObservableAsync <IAsyncReactiveQbservable <T>, TimeSpan, IList <T> >(new Uri(Client.Constants.Observable.Buffer.TimeDuration), (source, duration) => source.AsSync().Buffer(duration).To <IReactiveQbservable <IList <T> >, IAsyncReactiveQbservable <IList <T> > >(), null, CancellationToken.None).ConfigureAwait(false);

            await context.DefineObservableAsync <IAsyncReactiveQbservable <T>, TimeSpan, TimeSpan, IList <T> >(new Uri(Client.Constants.Observable.Buffer.TimeDurationShift), (source, duration, shift) => source.AsSync().Buffer(duration, shift).To <IReactiveQbservable <IList <T> >, IAsyncReactiveQbservable <IList <T> > >(), null, CancellationToken.None).ConfigureAwait(false);

            await context.DefineObservableAsync <IAsyncReactiveQbservable <T>, int, IList <T> >(new Uri(Client.Constants.Observable.Buffer.Count), (source, count) => source.AsSync().Buffer(count).To <IReactiveQbservable <IList <T> >, IAsyncReactiveQbservable <IList <T> > >(), null, CancellationToken.None).ConfigureAwait(false);

            await context.DefineObservableAsync <IAsyncReactiveQbservable <T>, int, int, IList <T> >(new Uri(Client.Constants.Observable.Buffer.CountSkip), (source, count, skip) => source.AsSync().Buffer(count, skip).To <IReactiveQbservable <IList <T> >, IAsyncReactiveQbservable <IList <T> > >(), null, CancellationToken.None).ConfigureAwait(false);

            await context.DefineObservableAsync <IAsyncReactiveQbservable <T>, TimeSpan, int, IList <T> >(new Uri(Client.Constants.Observable.Buffer.TimeCount), (source, duration, count) => source.AsSync().Buffer(duration, count).To <IReactiveQbservable <IList <T> >, IAsyncReactiveQbservable <IList <T> > >(), null, CancellationToken.None).ConfigureAwait(false);

            await context.DefineObservableAsync <IAsyncReactiveQbservable <T>, Expression <Func <T, T1> >, IAsyncReactiveGroupedQbservable <T1, T> >(new Uri(Client.Constants.Observable.GroupBy.Key), (source, keySelector) => source.AsSync().GroupBy(keySelector).To <IReactiveQbservable <IReactiveGroupedQbservable <T1, T> >, IAsyncReactiveQbservable <IAsyncReactiveGroupedQbservable <T1, T> > >(), null, CancellationToken.None).ConfigureAwait(false);

            await context.DefineObservableAsync <IAsyncReactiveQbservable <T>, Expression <Func <T, T1> >, Expression <Func <T, T2> >, IAsyncReactiveGroupedQbservable <T1, T2> >(new Uri(Client.Constants.Observable.GroupBy.KeyElement), (source, keySelector, elementSelector) => source.AsSync().GroupBy(keySelector, elementSelector).To <IReactiveQbservable <IReactiveGroupedQbservable <T1, T2> >, IAsyncReactiveQbservable <IAsyncReactiveGroupedQbservable <T1, T2> > >(), null, CancellationToken.None).ConfigureAwait(false);

            // Extension defines
            await DefineOperatorsExtension(context).ConfigureAwait(false);
        }
Exemple #2
0
        public static async Task RunAsync()
        {
            //
            // Define a stream manager that will be made available to Source<T> and Sink<T> through the operator context.
            // The state of the stream manager itself is not persisted as part of a checkpoint, so we keep the instance alive across engine lifetimes.
            //

            var sm = new StreamManager();

            //
            // Create two streams: xs will be used by Source<T> to send events into the computation, and ys will be used by Sink<T> to receive results.
            //

            var xs = sm.CreateSubject <int>("xs");
            var ys = sm.CreateSubject <string>("ys");

            //
            // For diagnostic purposes, we'll always listen to the sink. Regardless of engine failover, we should see events here.
            //

            ys.Subscribe(Console.WriteLine);

            //
            // We'll reuse a few more things across engine failovers:
            //
            // - a physical scheduler to obtain logical schedulers from
            // - an in-memory key/value store for the create/delete transactions (note we could save/load this one, but it doesn't intersect with operator local storage functionality)
            //

            var physicalScheduler = PhysicalScheduler.Create();
            var kvs = new InMemoryKeyValueStore();

            //
            // We'll have two generations of the same engine, similating a checkpoint/recover transition. The only piece of shared state will be the in-memory checkpoint store.
            //

            var checkpointStore = new Store();

            //
            // First generation of the engine.
            //

            {
                //
                // Instantiate an engine with:
                //
                // - a no-op resolver; we're never going to rely on binding to artifacts defined outside this engine
                // - a no-op registry; we'll define all artifacts inside the engine rather than relying on a central catalog
                // - a shared in-memory key/value store for transactions (see above)
                // - a logical scheduler, no trace source, and the simplest of compiled delegate caches available
                // - an operator context element added for Source<T> and Sink<T> to get access to the stream manager
                //

                var engine = new Engine.CheckpointingQueryEngine(new Uri("qe://demo/1"), new Resolver(), new LogicalScheduler(physicalScheduler), new Registry(), kvs, s_map, traceSource: null, new SimpleCompiledDelegateCache())
                {
                    OperatorContextElements =
                    {
                        { "StreamManager", sm }
                    }
                };

                //
                // Get an IReactive wrapper around the engine for programming ergonomics below.
                //

                var ctx = new QueryEngineContext(engine.ReactiveService);

                //
                // For the first instance of the engine, we'll define a bunch of artifacts which will be checkpointed, including our custom buffer operator using operator local storage.
                //

                {
                    ctx.DefineObservable(
                        new Uri("observable://source"),
                        CastVisitor.Apply((Expression <Func <string, IReactiveQbservable <T> > >)(stream => new Source <T>(stream).ToQbservable())),
                        null);

                    ctx.DefineObserver(
                        new Uri("observer://sink"),
                        CastVisitor.Apply((Expression <Func <string, IReactiveQbserver <T> > >)(stream => new Sink <T>(stream).ToQbserver())),
                        null);

                    ctx.DefineObservable <IReactiveQbservable <T>, Expression <Func <T, R> >, R>(
                        new Uri("rx://observable/map"),
                        (source, selector) => ReactiveQbservable.Select(source, selector),
                        null);

                    ctx.DefineObservable <IReactiveQbservable <T>, int, int, IList <T> >(
                        new Uri("rx://observable/buffer"),
#if USE_OLS
                        CastVisitor.Apply((Expression <Func <IReactiveQbservable <T>, int, int, IReactiveQbservable <IList <T> > > >)((source, count, skip) => new BufferCountSkip <T>(source.ToSubscribable(), count, skip).ToQbservable())),
#else
                        (source, count, skip) => ReactiveQbservable.Buffer(source, count, skip),
#endif
                        null);
                }

                //
                // For the first instance of the engine, we'll also define our standing query which will be checkpointed.
                //

                {
                    var source = ctx.GetObservable <string, int>(new Uri("observable://source"))("xs");

                    var select = ctx.GetObservable <IReactiveQbservable <IList <int> >, Expression <Func <IList <int>, string> >, string>(new Uri("rx://observable/map"));
                    var buffer = ctx.GetObservable <IReactiveQbservable <int>, int, int, IList <int> >(new Uri("rx://observable/buffer"));

                    var sink = ctx.GetObserver <string, string>(new Uri("observer://sink"))("ys");

                    select(buffer(source, 5, 3), list => string.Join(", ", list)).Subscribe(sink, new Uri("subscription://demo"), null);
                }

                //
                // We'll send events in range [0..9] which should emit two buffers ([0..4] and [3..7]) and have two buffers pending ([6..10] and [9..13]).
                //
                //                                      Failure
                //                                         |
                //   0,  1,  2,  3,  4,  5,  6,  7,  8,  9,|10, 11, 12, 13, 14, 15, 16, 17, 18, 19
                // [------------------]                    |
                //             [------------------]        |
                //                         [---------------|--]
                //                                     [---|--------------]
                //                                         |       [------------------]
                //                                         |                   [------------------]
                //                                         |
                //
                // In order to wait for the delivery of the first two buffers, we'll subscribe to ys outside the engine ourselves to obtain a task to await on.
                // This is needed because event processing in the engine happens asynchronously on scheduler threads.
                //

                var afterTwoEvents = ys.Take(2).ToTask();

                for (var i = 0; i <= 9; i++)
                {
                    xs.OnNext(i);
                }

                await afterTwoEvents;

                //
                // Now it's time to checkpoint the engine.
                //
                // NB: We have to use the "long" overload here because it's the only one we supply in our extension to CheckpointingQueryEngine.
                //

                await engine.CheckpointAsync(new StateWriter(checkpointStore, CheckpointKind.Differential), CancellationToken.None, progress : null);

                //
                // To make our testing easier, we'll call UnloadAsync, which enables our Source<T> to detach from the stream manager.
                //

                await engine.UnloadAsync();
            }

            //
            // Print the store.
            //

            checkpointStore.Print();

            //
            // Second generation of the engine.
            //

            {
                //
                // Re-instantiate the engine with parameters similar to the ones used the first time around.
                //

                var engine = new Engine.CheckpointingQueryEngine(new Uri("qe://demo/1"), new Resolver(), new LogicalScheduler(physicalScheduler), new Registry(), kvs, s_map, traceSource: null, new SimpleCompiledDelegateCache())
                {
                    OperatorContextElements =
                    {
                        { "StreamManager", sm }
                    }
                };

                //
                // Recover the engine from state.
                //
                // NB: We have to use the "long" overload here because it's the only one we supply in our extension to CheckpointingQueryEngine.
                //

                await engine.RecoverAsync(new StateReader(checkpointStore), CancellationToken.None, progress : null);

                //
                // We'll continue to send events in range [10..19] which should emit the two buffers that were pending ([6..10] and [9..13]) and two new buffers ([12..16] and [15..19]).
                //
                //                                      Failure
                //                                         |
                //   0,  1,  2,  3,  4,  5,  6,  7,  8,  9,|10, 11, 12, 13, 14, 15, 16, 17, 18, 19
                // [------------------]                    |
                //             [------------------]        |
                //                         [---------------|--]
                //                                     [---|--------------]
                //                                         |       [------------------]
                //                                         |                   [------------------]
                //                                         |
                //
                // In order to wait for the delivery of the next four buffers, we'll subscribe to ys outside the engine ourselves to obtain a task to await on.
                // This is needed because event processing in the engine happens asynchronously on scheduler threads.
                //

                var afterFourEvents = ys.Take(4).ToTask();

                for (var i = 10; i <= 19; i++)
                {
                    xs.OnNext(i);
                }

                await afterFourEvents;
            }
        }