/// <summary> /// Subscribes the specified aggregator to a catchup. /// </summary> /// <typeparam name="TProjection">The type of the projection.</typeparam> /// <typeparam name="TData">The type of the stream's data.</typeparam> /// <typeparam name="TCursor">The type of the cursor.</typeparam> /// <param name="catchup">The catchup.</param> /// <param name="aggregator">The aggregator.</param> /// <returns>A disposable that, when disposed, unsubscribes the aggregator.</returns> public static IDisposable Subscribe <TProjection, TData, TCursor>( this IStreamCatchup <TData, TCursor> catchup, IStreamAggregator <TProjection, TData> aggregator, FetchAndSaveProjection <TProjection> manageProjection, HandleAggregatorError <TProjection> onError = null) { return(catchup.SubscribeAggregator(aggregator, manageProjection, onError)); }
public static FetchAndSaveProjection <TProjection> Catch <TProjection>( this FetchAndSaveProjection <TProjection> fetchAndSaveProjection, HandleAggregatorError <TProjection> onError) { return(async(id, aggregate) => { Exception innerException = null; try { await fetchAndSaveProjection(id, async projection => { var resultingProjection = default(TProjection); try { resultingProjection = await aggregate(projection); } catch (Exception exception) { var error = CheckErrorHandler(onError, exception, projection); if (!error.ShouldContinue) { throw; } innerException = exception; return error.Projection; } return resultingProjection; }); } catch (Exception exception) { if (exception != innerException) { var error = CheckErrorHandler(onError, exception); if (!error.ShouldContinue) { throw; } } } }); }
internal static StreamCatchupError <TProjection> CheckErrorHandler <TProjection>( this HandleAggregatorError <TProjection> onError, Exception exception, TProjection projection = default(TProjection)) { var error = new StreamCatchupError <TProjection> { Exception = exception, Projection = projection }; onError(error); return(error); }
public IDisposable SubscribeAggregator <TProjection>( IStreamAggregator <TProjection, TData> aggregator, FetchAndSaveProjection <TProjection> fetchAndSaveProjection, HandleAggregatorError <TProjection> onError) { var added = aggregatorSubscriptions.TryAdd(typeof(TProjection), new AggregatorSubscription <TProjection, TData>(aggregator, fetchAndSaveProjection, onError)); if (!added) { throw new InvalidOperationException(string.Format("Aggregator for projection of type {0} is already subscribed.", typeof(TProjection))); } return(Disposable.Create(() => { IAggregatorSubscription _; aggregatorSubscriptions.TryRemove(typeof(TProjection), out _); })); }
public AggregatorSubscription( IStreamAggregator <TProjection, TData> aggregator, FetchAndSaveProjection <TProjection> fetchAndSaveProjection = null, HandleAggregatorError <TProjection> onError = null) { if (aggregator == null) { throw new ArgumentNullException("aggregator"); } OnError = onError ?? (error => { }); if (onError != null) { fetchAndSaveProjection = fetchAndSaveProjection.Catch(onError); } FetchAndSaveProjection = fetchAndSaveProjection ?? (async(streamId, aggregate) => { await aggregate(Activator.CreateInstance <TProjection>()); }); Aggregator = aggregator; }