/// <summary> /// Chain the next request using (MessagePack) binary serialized data. /// TPayload is the type that the received actor will try to deserialize payload to. /// </summary> /// <typeparam name="TPayload"></typeparam> /// <param name="requestContext"></param> /// <param name="payload"></param> /// <param name="actionName"></param> /// <param name="cancellationToken"></param> /// <returns></returns> protected virtual async Task ChainRequestAsync <TPayload>(ActorRequestContext requestContext, byte[] payload, string actionName = null, CancellationToken cancellationToken = default(CancellationToken)) { var isRequestValid = ValidateRequestAsync(requestContext, cancellationToken); if (isRequestValid.Result) { try { //serialize back to object var deserializedPayload = DeserializePayload <TPayload>(payload); #pragma warning disable 618 await ChainRequestAsync(requestContext, deserializedPayload, actionName, cancellationToken); #pragma warning restore 618 } catch (Exception ex) { Logger.LogError(ex, $"[{CurrentActor}-ChainRequestAsync]Failed to deserialize of type {typeof(TPayload)}: " + ex.Message); throw; } } else { var exception = new ActorRequestInvalidException( $"Actor Request {requestContext.RequestId} with action name {requestContext.ActionName} from {requestContext.ManagerId} is failed to validate and will not be processed by actor {Id} of the service {ActorService.ActorTypeInformation.ServiceName}. The exception will be propagated to the caller and possibly result in a retry."); Logger.LogError(exception, exception.Message); throw exception; } }
public virtual async Task SaveRequest(string actionName, ActorRequestContext actorRequestContext, Type typeOfPayload, byte[] entity, CancellationToken cancellationToken) { try { await StateManager.AddStateAsync(NameCompositionResolver.GenerateRequestContextStateName(actionName, actorRequestContext.RequestId), actorRequestContext, cancellationToken); await StateManager.AddStateAsync(NameCompositionResolver.GenerateRequestPayloadStateName(actionName, actorRequestContext.RequestId), entity, cancellationToken); await StateManager.AddStateAsync(NameCompositionResolver.GenerateRequestPayloadTypeStateName(actionName, actorRequestContext.RequestId), typeOfPayload.AssemblyQualifiedName, cancellationToken); //As cancellation token cant be serialized & replicated to other node and cant be used to invoke cancellation //await StateManager.AddStateAsync(NameCompositionResolver.GenerateRequestCanncellationTokenStateName(actionName, actorRequestContext.RequestId), cancellationToken, cancellationToken); //UnComment if wantting to deal with status of the requests /* * await StateManager.AddStateAsync( * NameCompositionResolver.GenerateRequestStateStateName(actionName, * actorRequestContext.RequestId), false, cancellationToken); * //add current latest reminder name for any current info. due to the single thread behaviour of actors, this is valid * await StateManager.AddOrUpdateStateAsync(ACTOR_REMINDER_LATEST_STATE_NAME, NameCompositionResolver.GenerateReminderName(actionName, actorRequestContext.RequestId), * (s, reminderName) => reminderName, cancellationToken); */ } catch (InvalidOperationException ex) { //add an already existed state //throw; } }
public async Task ChainNextActorAsync(ActorRequestContext nextActorRequestContext, object payload, Type typeOfPayload, ActorIdentity actorIdentity, CancellationToken cancellationToken) { if (actorIdentity?.ActorId == null || actorIdentity?.ActorServiceUri == null) { throw new ArgumentNullException($"MessagingActorClient failed at ChainNextActorAsync due to null of {nameof(actorIdentity)}. The client could not chain to next actor which is null."); } //put more logic on to the orchestration collection later. Now it is just get the single one var proxy = ActorProxy.Create <IBaseMessagingActor>( new ActorId(actorIdentity.ActorId), new Uri(actorIdentity.ActorServiceUri)); var serializedPayload = _binaryMessageSerializer.SerializePayload(payload, typeOfPayload); try { await proxy.ChainProcessMessageAsync(nextActorRequestContext, serializedPayload, cancellationToken); } catch (System.Fabric.FabricServiceNotFoundException) { if (actorIdentity.ActorServiceUri.Equals(Constants.DetourConstants.DEFAULT_GENERIC_DETOUR_ACTOR, StringComparison.OrdinalIgnoreCase)) { if ((dynamic)payload is DetourPayload detourPayload) { serializedPayload = _binaryMessageSerializer.SerializePayload(detourPayload.NextActorPayload); proxy = ActorProxy.Create <IBaseMessagingActor>( new ActorId(detourPayload.NextActorId), new Uri(detourPayload.DefaultNextActorUri)); await proxy.ChainProcessMessageAsync(nextActorRequestContext, serializedPayload, cancellationToken); } } throw; } }
/// <summary> /// Wrapper for orchestration-order to be converted to executable order /// </summary> /// <typeparam name="T"></typeparam> /// <param name="nextActorRequestContext"></param> /// <param name="payload"></param> /// <param name="order"></param> /// <param name="cancellationToken"></param> /// <returns></returns> protected virtual async Task ChainNextActorsAsync(ActorRequestContext nextActorRequestContext, object payload, Type typeOfPayload, OrchestrationOrder order, CancellationToken cancellationToken) { //put more logic on to the orchestration collection later. Now it is just get the single one var anotherOrderInMyActorLifeTime = order.ToExecutableOrder(); await ChainNextActorsAsync(nextActorRequestContext, payload, typeOfPayload, anotherOrderInMyActorLifeTime, cancellationToken); //just do nothing because no order }
protected virtual async Task ChainNextActorsAsync(ActorRequestContext nextActorRequestContext, object payload, Type typeOfPayload, CancellationToken cancellationToken) { // if having any request-order if (!Orders.IsEmpty) { //put more logic on to the orchestration collection later. Now it is just get the single one var anotherOrderInMyActorLifeTime = Orders.GetFirstExecutableOrder(); await ChainNextActorsAsync(nextActorRequestContext, payload, typeOfPayload, anotherOrderInMyActorLifeTime, cancellationToken); } //just do nothing because no order }
public async Task ChainNextActorAsync(ActorRequestContext nextActorRequestContext, object payload, Type typeOfPayload, ActorIdentity actorIdentity, CancellationToken cancellationToken) { if (actorIdentity?.ActorId == null || actorIdentity?.ActorServiceUri == null) { throw new ArgumentNullException($"MessagingActorClient failed at ChainNextActorAsync due to null of {nameof(actorIdentity)}. The client could not chain to next actor which is null."); } //put more logic on to the orchestration collection later. Now it is just get the single one var proxy = ActorProxy.Create <IBaseMessagingActor>( new ActorId(actorIdentity.ActorId), new Uri(actorIdentity.ActorServiceUri)); var serializedPayload = _binaryMessageSerializer.SerializePayload(payload, typeOfPayload); await proxy.ChainProcessMessageAsync(nextActorRequestContext, serializedPayload, cancellationToken); }
/// <summary> /// Main method to chain an order take in an executable order /// Allow actors to directly make call to next actor via an executable order object /// </summary> /// <typeparam name="T"></typeparam> /// <param name="nextActorRequestContext"></param> /// <param name="payload"></param> /// <param name="excutableOrder"></param> /// <param name="cancellationToken"></param> /// <returns></returns> protected virtual async Task ChainNextActorsAsync(ActorRequestContext nextActorRequestContext, object payload, Type typeOfPayload, ExecutableOrchestrationOrder excutableOrder, CancellationToken cancellationToken) { //try to complete the step await CompleteStepAsync(payload); try { await ActorClient.ChainNextActorAsync(nextActorRequestContext, payload, typeOfPayload, new ActorIdentity(excutableOrder.ActorId, excutableOrder.ActorServiceUri), cancellationToken); } catch (Exception ex) { Logger.LogError(ex, $"{CurrentActor} failed to chain next actor {excutableOrder?.ActorServiceUri} with actor id {excutableOrder?.ActorId}. Message: {ex.Message}"); } }
public async Task <string> SaveMessageAsync(ActorRequestContext actorRequestContext, string key, byte[] payload, CancellationToken cancellationToken) { try { // save message => schedule to delete after TTL await RegisterReminderAsync(TTL_REMINDER_NAME, null, TimeSpan.FromDays(MAX_TTL_IN_MINUTE), TimeSpan.FromMilliseconds(-1)); await StateManager.AddOrUpdateStateAsync(key, payload, (k, v) => payload, cancellationToken); return(key); } catch (System.Exception ex) { Logger.LogError(ex, $"Failed to store the variable with key {key}."); return(SAVED_ERROR); } }
protected async Task ChainNextActorAsync(ActorRequestContext nextActorRequestContext, string startedPayload, object nextPayload, Type typeOfPayload, ExecutableOrchestrationOrder order, CancellationToken cancellationToken) { var flowInstanceId = nextActorRequestContext.FlowInstanceId; // var startedFlowInstanceId = new FlowInstanceId(Activity.Current.Id, (this.GetType().Name)); var applicationName = Context.CodePackageActivationContext.ApplicationName; await TryCreateFlow(applicationName, flowInstanceId, startedPayload); var uri = new Uri(order.ActorServiceUri); //var startedFlowInstanceId = new FlowInstanceId(Activity.Current.Id, (this.GetType().Name)); var proxy = ActorProxy.Create <IBaseMessagingActor>(order.ActorId == null ? ActorId.CreateRandom() : new ActorId(order.ActorId), uri); var payload = BinaryMessageSerializer.SerializePayload(nextPayload); await proxy.ChainProcessMessageAsync(nextActorRequestContext, payload, cancellationToken); }
public async Task <byte[]> RetrieveMessageAsync(ActorRequestContext actorRequestContext, string key, bool isOptional, CancellationToken cancellationToken) { try { //anytime a request to retrieve data, re-schedule reminder to new one await RegisterReminderAsync(TTL_REMINDER_NAME, null, TimeSpan.FromDays(MAX_TTL_IN_MINUTE), TimeSpan.FromMilliseconds(-1)); return(await StateManager.GetStateAsync <byte[]>(key)); } catch (System.Exception ex) { if (isOptional) { return(null); } Logger.LogError(ex, $"Failed to retrieve the variable with key {key} from {actorRequestContext?.ManagerId}."); throw; } }
/// <summary> /// Non generic version of ChainRequestAsync /// </summary> /// <param name="requestContext"></param> /// <param name="payload"></param> /// <param name="typeOfPayload"></param> /// <param name="actionName"></param> /// <param name="cancellationToken"></param> /// <returns></returns> protected virtual async Task ChainRequestAsyncNonGeneric(ActorRequestContext requestContext, byte[] payload, Type typeOfPayload, string actionName = null, CancellationToken cancellationToken = default(CancellationToken)) { try { //any specify reminder name? if not, use default var currentActionName = actionName ?? requestContext.ActionName; var currentReminderName = NameCompositionResolver.GenerateReminderName(currentActionName, requestContext.RequestId); //persist request to state await ActorRequestPersistence.SaveRequest(currentActionName, requestContext, typeOfPayload, payload, cancellationToken); // register reminder to process the request later await RegisterReminderAsync(currentReminderName, null, _dueTime, _periodTimeInfinite); } catch (Exception e) { Logger.LogError(e, $"[{CurrentActor}-ChainRequestAsync] Failed to chain request of type {typeOfPayload.Name}: " + e.Message); throw; } }
/// <summary> /// This method will allow supports for Flow&Step involed in the implementation without a strong type expression of the interface /// This method also help when we have methodName resolved by a serialized Step /// </summary> /// <param name="methodName"></param> /// <param name="actorRequestContext"></param> /// <param name="arguments"></param> /// <returns></returns> private static async Task Invoke(string methodName, ActorRequestContext actorRequestContext, params object[] arguments) { if (actorRequestContext?.TargetActor == null) { throw new ArgumentNullException(INVALID_TARGET_ACTOR_ERROR_MESSAGE); } var serializableMethodInfo = new SerializableMethodInfo(); serializableMethodInfo.MethodName = methodName; actorRequestContext.MethodName = methodName; foreach (var arg in arguments) { serializableMethodInfo.Arguments.Add(new SerializableMethodArgument() { ArgumentAssemblyType = arg.GetType().AssemblyQualifiedName, Value = _binaryMessageSerializer.SerializePayload(arg) }); } actorRequestContext.ActionName = actorRequestContext.ActionName; await _actorClient.ChainNextActorAsync <SerializableMethodInfo>(actorRequestContext, serializableMethodInfo, actorRequestContext.TargetActor, CancellationToken.None); }
public virtual async Task ChainProcessMessageAsync(ActorRequestContext actorRequestContext, byte[] payload, CancellationToken cancellationToken) { //Every action only work with SerializableMethodInfo class await ChainRequestAsync <SerializableMethodInfo>(actorRequestContext, payload, actorRequestContext.ActionName, cancellationToken); }
public ActorHttpAsyncHandler(ActorRequestContext context, TInput inputModel, Channel <TInput> input) { _context = context; _input = input; _inputModel = inputModel; }
protected abstract Task <bool> FlowInitialize(ActorRequestContext actorRequestContext, FlowInstanceId flowInstanceId, CancellationToken cancellationToken);
public static Task Invoke <TIActionInterface>(Expression <Func <TIActionInterface, object> > expression, ActorRequestContext actorRequestContext, ExecutableOrchestrationOrder executableOrchestrationOrder, CancellationToken cancellationToken) where TIActionInterface : IRemotableAction => ActionInvoker <TIActionInterface> .Invoke(expression, actorRequestContext, executableOrchestrationOrder, cancellationToken);
/// <summary> /// Validate request to see if the action name is already implemented on the actor or some failure with manager id /// Override when there is the need of that kind validation. Possible exception that could be thrown is ActorMessageValidationException and all of its deriveds /// </summary> /// <param name="requestContext"></param> /// <param name="cancellationToken"></param> /// <exception cref="ActorMessageValidationException"></exception> /// <exception cref="ActorRequestActionNameNotSupportedException"></exception> /// <returns></returns> protected virtual Task <bool> ValidateRequestAsync(ActorRequestContext requestContext, CancellationToken cancellationToken) { return(Task.FromResult(true)); }
public override async Task ChainProcessMessageAsync(ActorRequestContext actorRequestContext, byte[] payload, CancellationToken cancellationToken) { var serviceBusOption = Deserialize <ServiceBusOption>(payload); await ChainCreateEventBusListenersAsync(serviceBusOption); }
public Task ChainRequestAsync(ActorRequestContext actorRequestContext, byte[] payload, Type typeOfPayload, string actionName, CancellationToken cancellationToken) => Actor.ChainRequestAsync(actorRequestContext, payload, typeOfPayload, actionName, cancellationToken);
public Task ChainNextActorAsync <T>(ActorRequestContext nextActorRequestContext, T payload, ActorIdentity actorIdentity, CancellationToken cancellationToken) { return(ChainNextActorAsync(nextActorRequestContext, payload, typeof(T), actorIdentity, cancellationToken)); }
public Task ChainNextActorsAsync <TIActionInterface>(Expression <Func <TIActionInterface, object> > expression, ActorRequestContext actorRequestContext, ExecutableOrchestrationOrder executableOrchestrationOrder, CancellationToken cancellationToken) where TIActionInterface : IRemotableAction => Actor.ChainNextActorsAsync(expression, actorRequestContext, executableOrchestrationOrder, cancellationToken);
public static Task Invoke(string methodName, ActorRequestContext actorRequestContext, ExecutableOrchestrationOrder executableOrchestrationOrder, params object[] arguments) { actorRequestContext.TargetActor = new ActorIdentity(executableOrchestrationOrder.ActorId, executableOrchestrationOrder.ActorServiceUri); return(Invoke(methodName, actorRequestContext, arguments)); }
public Task ChainNextActorsAsync(ActorRequestContext actorRequestContext, object payload, Type typeOfPayload, ExecutableOrchestrationOrder executableOrchestrationOrder, CancellationToken cancellationToken) => Actor.ChainNextActorsAsync(actorRequestContext, payload, typeOfPayload, executableOrchestrationOrder, cancellationToken);
public virtual Task <bool> InitFlowAsync(ActorRequestContext actorRequestContext, FlowInstanceId flowInstanceId, CancellationToken cancellationToken) { FlowInstanceId = flowInstanceId; FlowServiceUri = actorRequestContext.ManagerService; return(FlowInitialize(actorRequestContext, flowInstanceId, cancellationToken)); }
public abstract Task ChainProcessMessageAsync(ActorRequestContext actorRequestContext, byte[] payload, CancellationToken cancellationToken);
public override Task ChainProcessMessageAsync(ActorRequestContext actorRequestContext, byte[] payload, CancellationToken cancellationToken) { return(Task.CompletedTask); }
/// <summary> /// Main method to chain an order take in an executable order /// Allow actors to directly make call to next actor via an executable order object /// </summary> /// <typeparam name="T"></typeparam> /// <param name="nextActorRequestContext"></param> /// <param name="payload"></param> /// <param name="excutableOrder"></param> /// <param name="cancellationToken"></param> /// <returns></returns> protected virtual async Task ChainNextActorsAsync <T>(ActorRequestContext nextActorRequestContext, T payload, ExecutableOrchestrationOrder excutableOrder, CancellationToken cancellationToken) { await ChainNextActorsAsync(nextActorRequestContext, payload, typeof(T), excutableOrder, cancellationToken); }