public static IEnumerable <T> SelectResults <T>(this FutureConsumeContext context) where T : class { return(context.Instance.HasResults() ? context.Instance.Results.Where(x => x.Value.HasMessageType <T>()).Select(x => x.Value.ToObject <T>()) : Enumerable.Empty <T>()); }
public async Task Execute(FutureConsumeContext <TInput> context) { var factory = context.GetStateMachineActivityFactory(); IItineraryPlanner <TInput> itineraryPlanner = factory.GetService <IItineraryPlanner <TInput> >(context); var trackingNumber = NewId.NextGuid(); var builder = new RoutingSlipBuilder(trackingNumber); builder.AddVariable(nameof(FutureConsumeContext.FutureId), context.FutureId); builder.AddSubscription(context.ReceiveContext.InputAddress, RoutingSlipEvents.Completed | RoutingSlipEvents.Faulted); await itineraryPlanner.PlanItinerary(context, builder).ConfigureAwait(false); var routingSlip = builder.Build(); await context.Execute(routingSlip).ConfigureAwait(false); if (TrackRoutingSlip) { context.Instance.Pending.Add(trackingNumber); } }
public static void SetFault <TFault>(this FutureConsumeContext context, Guid id, TFault fault, DateTime?timestamp = default) where TFault : class { SetFaulted(context, id, timestamp); context.Instance.Faults[id] = new FutureMessage <TFault>(fault); }
public Task SetFaulted(BehaviorContext <FutureState, TInput> context) { FutureConsumeContext <TInput> consumeContext = context.CreateFutureConsumeContext(); return(consumeContext.Instance.HasSubscriptions() ? _endpoint.SendFault(consumeContext, consumeContext.Instance.Subscriptions.ToArray()) : _endpoint.SendFault(consumeContext)); }
public async Task SendFault(FutureConsumeContext <TResult> context, params FutureSubscription[] subscriptions) { var fault = await _factory(context).ConfigureAwait(false); context.SetFault(context.Instance.CorrelationId, fault); await context.SendMessageToSubscriptions(subscriptions, fault).ConfigureAwait(false); }
static object MapOrderBurger(FutureConsumeContext <Burger> context) { return(new { OrderId = context.Instance.CorrelationId, OrderLineId = context.Message.BurgerId, Burger = context.Message }); }
public static void AddSubscription(this FutureConsumeContext context) { if (context.ResponseAddress == null) { return; } context.Instance.Subscriptions.Add(new FutureSubscription(context.ResponseAddress, context.RequestId)); }
static object MapOrderBurger <TPatty, TCondiments>(FutureConsumeContext <Burger <TPatty, TCondiments> > context) where TCondiments : Condiments { return(new { OrderId = context.Instance.CorrelationId, OrderLineId = context.Message.BurgerId, Burger = context.Message }); }
public static async Task <TValue> SetVariable <TValue>(this FutureConsumeContext context, string key, AsyncFutureMessageFactory <TValue> factory) where TValue : class { var value = await factory(context).ConfigureAwait(false); context.Instance.Variables[key] = value; return(value); }
static object MapOrderFry(FutureConsumeContext <Fry> context) { return(new { OrderId = context.Instance.CorrelationId, OrderLineId = context.Message.FryId, context.Message.Size, }); }
public static TValue SetVariable <TValue>(this FutureConsumeContext context, string key, FutureMessageFactory <TValue> factory) where TValue : class { var value = factory(context); context.Instance.Variables[key] = value; return(value); }
static object MapOrderShake(FutureConsumeContext <Shake> context) { return(new { OrderId = context.Instance.CorrelationId, OrderLineId = context.Message.ShakeId, context.Message.Size, context.Message.Flavor }); }
/// <summary> /// Use when a request is received after the initial request is still awaiting completion /// </summary> /// <param name="binder"></param> /// <typeparam name="T"></typeparam> /// <returns></returns> public static EventActivityBinder <FutureState, T> AddSubscription <T>(this EventActivityBinder <FutureState, T> binder) where T : class { return(binder.Then(context => { FutureConsumeContext <T> consumeContext = context.CreateFutureConsumeContext(context.Data); consumeContext.AddSubscription(); })); }
public static void SetResult <TResult>(this FutureConsumeContext context, Guid id, TResult result) where TResult : class { if (!context.Instance.Completed.HasValue) { SetCompleted(context, id); } context.Instance.Results[id] = new FutureMessage <TResult>(result); }
public static void SetFault <T, TFault>(this FutureConsumeContext <T> context, Guid id, FutureMessageFactory <T, TFault> factory) where T : class where TFault : class { SetFaulted(context, id); var result = factory(context); context.Instance.Faults[id] = new FutureMessage <TFault>(result); }
static object MapOrderFaulted(FutureConsumeContext context) { Dictionary <Guid, Fault> faults = context.Instance.Faults.ToDictionary(x => x.Key, x => x.Value.ToObject <Fault>()); return(new { LinesCompleted = context.Instance.Results.ToDictionary(x => x.Key, x => x.Value.ToObject <OrderLineCompleted>()), LinesFaulted = faults, Exceptions = faults.SelectMany(x => x.Value.Exceptions).ToArray() }); }
public static bool TryGetVariable <T>(this FutureConsumeContext future, string key, out T result) where T : class { if (future.Instance.HasVariables()) { return(future.Instance.Variables.TryGetValue(key, out result)); } result = default; return(false); }
public static EventActivityBinder <FutureState, TData> SetVariable <TData, TValue>(this EventActivityBinder <FutureState, TData> binder, string key, AsyncFutureMessageFactory <TData, TValue> valueFactory) where TData : class where TValue : class { return(binder.Add(new AsyncActivity <FutureState, TData>(context => { FutureConsumeContext <TData> futureContext = context.CreateFutureConsumeContext(context.Data); return futureContext.SetVariable(key, valueFactory); }))); }
/// <summary> /// Set the result associated with the identifier using the message factory /// </summary> /// <param name="binder"></param> /// <param name="messageFactory">Should return the result message</param> /// <typeparam name="TResult">The result type</typeparam> /// <returns></returns> public static EventActivityBinder <FutureState, RoutingSlipFaulted> SetFault <TResult>(this EventActivityBinder <FutureState, RoutingSlipFaulted> binder, FutureMessageFactory <RoutingSlipFaulted, TResult> messageFactory) where TResult : class { return(binder.Then(context => { FutureConsumeContext <RoutingSlipFaulted> consumeContext = context.CreateFutureConsumeContext(); var resultId = consumeContext.Message.TrackingNumber; consumeContext.SetFault(resultId, messageFactory); })); }
public static void SetResult <T, TResult>(this FutureConsumeContext <T> context, Guid id, FutureMessageFactory <T, TResult> factory) where T : class where TResult : class { if (!context.Instance.Completed.HasValue) { SetCompleted(context, id); } var result = factory(context); context.Instance.Results[id] = new FutureMessage <TResult>(result); }
public static void SetFaulted(this FutureConsumeContext context, Guid id, DateTime?timestamp = default) { timestamp ??= context.SentTime ?? DateTime.UtcNow; var future = context.Instance; if (future.HasPending()) { future.Pending?.Remove(id); } future.Faulted ??= timestamp; }
public static async Task <TResult> SetResult <TResult>(this FutureConsumeContext context, Guid id, AsyncFutureMessageFactory <TResult> factory) where TResult : class { if (!context.Instance.Completed.HasValue) { SetCompleted(context, id); } var result = await factory(context).ConfigureAwait(false); context.Instance.Results[id] = new FutureMessage <TResult>(result); return(result); }
/// <summary> /// Set the result associated with the identifier using the message factory /// </summary> /// <param name="binder"></param> /// <param name="getResultId">Should return the result identifier</param> /// <param name="messageFactory">Should return the result message</param> /// <typeparam name="T">The event type</typeparam> /// <typeparam name="TResult">The result type</typeparam> /// <returns></returns> public static EventActivityBinder <FutureState, T> SetResult <T, TResult>(this EventActivityBinder <FutureState, T> binder, Func <FutureConsumeContext <T>, Guid> getResultId, FutureMessageFactory <T, TResult> messageFactory) where T : class where TResult : class { return(binder.Then(context => { FutureConsumeContext <T> consumeContext = context.CreateFutureConsumeContext(); var resultId = getResultId(consumeContext); consumeContext.SetResult(resultId, messageFactory); })); }
/// <summary> /// Initialize the FutureState properties of the request /// </summary> /// <param name="binder"></param> /// <typeparam name="T"></typeparam> /// <returns></returns> public static EventActivityBinder <FutureState, T> InitializeFuture <T>(this EventActivityBinder <FutureState, T> binder) where T : class { return(binder .Then(context => { FutureConsumeContext <T> consumeContext = context.CreateFutureConsumeContext(context.Data); context.Instance.Created = DateTime.UtcNow; context.Instance.Command = new FutureMessage <T>(consumeContext.Message); context.Instance.Location = new FutureLocation(context.Instance.CorrelationId, consumeContext.ReceiveContext.InputAddress); consumeContext.AddSubscription(); })); }
static object RoutingSlipFaultedValueProvider(FutureConsumeContext <RoutingSlipFaulted> context) { var message = context.Instance.GetCommand <TCommand>(); IEnumerable <ExceptionInfo> exceptions = context.Message.ActivityExceptions.Select(x => x.ExceptionInfo); return(new { FaultId = context.MessageId ?? NewId.NextGuid(), FaultedMessageId = context.Message.TrackingNumber, FaultMessageTypes = TypeMetadataCache <TCommand> .MessageTypeNames, Host = context.Message.ActivityExceptions.Select(x => x.Host).FirstOrDefault() ?? context.Host, context.Message.Timestamp, exceptions, message }); }
async Task Execute(FutureConsumeContext <T> consumeContext) { // this will need to be done by a consumer at some point, to handle retry/fault handling var trackingNumber = NewId.NextGuid(); var builder = new RoutingSlipBuilder(trackingNumber); builder.AddVariable(nameof(consumeContext.FutureId), consumeContext.FutureId); builder.AddSubscription(consumeContext.ReceiveContext.InputAddress, RoutingSlipEvents.Completed | RoutingSlipEvents.Faulted); await _planner.PlanItinerary(consumeContext.Message, builder).ConfigureAwait(false); var routingSlip = builder.Build(); await consumeContext.Execute(routingSlip).ConfigureAwait(false); }
public async Task PlanItinerary(FutureConsumeContext <OrderBurger> context, ItineraryBuilder builder) { var orderBurger = context.Message; builder.AddVariable(nameof(OrderBurger.OrderId), orderBurger.OrderId); builder.AddVariable(nameof(OrderBurger.OrderLineId), orderBurger.OrderLineId); var burger = orderBurger.Burger; builder.AddActivity(nameof(GrillBurgerActivity), _grillAddress, new { burger.Weight, burger.Cheese, }); Guid?onionRingId = default; if (burger.OnionRing) { onionRingId = NewId.NextGuid(); // TODO create a future with address/id await context.Publish <OrderOnionRings>(new { orderBurger.OrderId, OrderLineId = onionRingId, Quantity = 1 }); } builder.AddActivity(nameof(DressBurgerActivity), _dressAddress, new { burger.Lettuce, burger.Pickle, burger.Onion, burger.Ketchup, burger.Mustard, burger.BarbecueSauce, burger.OnionRing, onionRingId }); }
public static void SetCompleted(this FutureConsumeContext context, Guid id) { var timestamp = context.SentTime ?? DateTime.UtcNow; var future = context.Instance; if (future.HasPending()) { future.Pending.Remove(id); if (!future.HasPending() && !future.HasFaults()) { future.Completed = timestamp; } } else if (!future.HasFaults()) { future.Completed = timestamp; } }
public async Task SendResponse(FutureConsumeContext <TResponse> context, params FutureSubscription[] subscriptions) { context.SetCompleted(context.Instance.CorrelationId); InitializeContext <TResult> initializeContext = await MessageInitializerCache <TResult> .Initialize(new { context.Instance.Completed, context.Instance.Created, context.Instance.Faulted, context.Instance.Location, }, context.CancellationToken); var request = context.Instance.GetCommand <TCommand>(); if (request != null) { initializeContext = await MessageInitializerCache <TResult> .Initialize(initializeContext, request); } if (context.Message != null) { initializeContext = await MessageInitializerCache <TResult> .Initialize(initializeContext, context.Message); } // this is due to the way headers are propagated via the initializer var values = _provider(context); IMessageInitializer <TResult> initializer = MessageInitializerCache <TResult> .GetInitializer(values.GetType()); var result = await context.SendMessageToSubscriptions(subscriptions, initializer, initializeContext, values).ConfigureAwait(false); if (result == null) { // initialize the message and save it as the response InitializeContext <TResult> messageContext = await initializer.Initialize(initializeContext, values).ConfigureAwait(false); result = messageContext.Message; } context.SetResult(context.Instance.CorrelationId, result); }
public async Task Execute(FutureConsumeContext <TInput> context) { var trackingNumber = NewId.NextGuid(); var builder = new RoutingSlipBuilder(trackingNumber); builder.AddVariable(nameof(FutureConsumeContext.FutureId), context.FutureId); builder.AddSubscription(context.ReceiveContext.InputAddress, RoutingSlipEvents.Completed | RoutingSlipEvents.Faulted); await _buildItinerary(context, builder).ConfigureAwait(false); var routingSlip = builder.Build(); await context.Execute(routingSlip).ConfigureAwait(false); if (TrackRoutingSlip) { context.Instance.Pending.Add(trackingNumber); } }