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 Task <string> StoreMessageAsync(string key, object payload, Type typeOfPayload, CancellationToken cancellationToken)
        {
            var serializedData = BinaryMessageSerializer.SerializePayload(payload, typeOfPayload);
            var proxy          = ActorProxy.Create <IStorageActor>(new ActorId($"{NameCompositionResolver.ExtractFlowInstanceIdFromFlowVariableKey(key)}"), StorageServiceUri);

            return(proxy.SaveMessageAsync(new ActorRequestContext(Guid.NewGuid().ToString(), null, Guid.NewGuid().ToString()), key, serializedData, cancellationToken));
        }
        public async Task <object> RetrieveMessageAsync(string key, Type typeOfPayload, CancellationToken cancellationToken)
        {
            var proxy   = ActorProxy.Create <IStorageActor>(new ActorId($"{NameCompositionResolver.ExtractFlowInstanceIdFromFlowVariableKey(key)}"), StorageServiceUri);
            var rawData = await proxy.RetrieveMessageAsync(new ActorRequestContext(Guid.NewGuid().ToString(), null, Guid.NewGuid().ToString()), key, false, cancellationToken);

            var data = rawData == null ? null : BinaryMessageSerializer.DeserializePayload(rawData, typeOfPayload);

            return(data);
        }
        /// <summary>
        /// Add flowinstance id to key
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        protected string MakeFlowVariableKey(string key)
        {
            if (CurrentFlowInstanceId?.Id == null || CurrentFlowInstanceId?.Id == NOT_ASSIGNED_FLOW_INSTANCE)
            {
                throw new ArgumentException($"{CurrentActor} failed to make flow variable as current flowinstance id is not valid");
            }

            if (!IsGlobalVariableKey(key))
            {
                return(NameCompositionResolver.GenerateFlowVariableStorageKey(key, CurrentFlowInstanceId?.Id));
            }
            return(key);
        }
        public async Task <Type> RetrieveRequestPayloadTypeAsync(string actionName, string requestId, CancellationToken cancellationToken)
        {
            try
            {
                var fullNameType = await StateManager.GetStateAsync <string>(NameCompositionResolver.GenerateRequestPayloadTypeStateName(actionName, requestId));

                if (fullNameType == null)
                {
                    return(null);
                }
                return(Type.GetType(fullNameType));
            }
            catch (Exception ex)
            {
                return(null);
            }
        }
Esempio n. 6
0
        /// <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;
            }
        }
 public async Task <CancellationToken> RetrieveRequestCancellationToken(string actionName, string requestId)
 {
     return(await StateManager.GetStateAsync <CancellationToken>(NameCompositionResolver.GenerateRequestCanncellationTokenStateName(actionName, requestId)));
 }
 public async Task <ActorRequestContext> RetrieveRequestContextAsync(string actionName, string requestId, CancellationToken cancellationToken)
 {
     return(await StateManager.GetStateAsync <ActorRequestContext>(NameCompositionResolver.GenerateRequestContextStateName(actionName, requestId)));
 }
 public async Task <TModel> RetrieveRequestPayloadAsync <TModel>(string actionName, string requestId, CancellationToken cancellationToken)
 {
     return(await StateManager.GetStateAsync <TModel>(NameCompositionResolver.GenerateRequestPayloadStateName(actionName, requestId)));
 }
Esempio n. 10
0
 public bool IsRequestPersistenceReminder(string reminderName)
 {
     return(NameCompositionResolver.IsValidRequestPersistenceForNonBlocking(reminderName));
 }
Esempio n. 11
0
        /// <summary>
        /// Reminder will tick very quickly after the actor saves request to state.
        /// Reminder will load up states based on reminder names and pass to InternalProcessAsync
        /// </summary>
        /// <param name="reminderName"></param>
        /// <param name="state"></param>
        /// <param name="dueTime"></param>
        /// <param name="period"></param>
        /// <returns></returns>
        public virtual async Task ReceiveReminderAsync(string reminderName, byte[] state, TimeSpan dueTime, TimeSpan period)
        {
            if (IsRequestPersistenceReminder(reminderName))
            {
                object            payload           = null;
                CancellationToken cancellationToken = CancellationToken.None;
                var actionName = NameCompositionResolver.ExtractActionNameFromReminderName(reminderName);

                try
                {
                    var currentRequestContextId =
                        NameCompositionResolver.ExtractRequestContextIdFromReminderName(reminderName);

                    //assign memory values, can be done with get/set
                    CurrentRequestContext = await
                                            ActorRequestPersistence.RetrieveRequestContextAsync(actionName, currentRequestContextId,
                                                                                                cancellationToken);

                    payload =
                        await ActorRequestPersistence.RetrieveRequestPayloadAsync <object>(actionName, currentRequestContextId,
                                                                                           cancellationToken);

                    //{current actor} only resolved fully from here, when current request context is available
                    var serviceName = this.ActorService.Context.ServiceName;

                    var dict = new Dictionary <string, object> {
                        { "ServiceUri", serviceName },
                        { "Payload", null },
                        { "ActionName", actionName },
                        { "Actor", CurrentActor },
                        { "ReminderName", reminderName },
                        { "OperationId", CurrentFlowInstanceId.Id },
                        { "FlowName", CurrentFlowInstanceId.FlowName },
                        { "ApplicationName", ApplicationName },
                        { "Resendable", false }
                    };

                    LogPayload(payload, actionName, dict, null, reminderName);

                    //for non-generic cases
                    var typeOfPayload = await ActorRequestPersistence.RetrieveRequestPayloadTypeAsync(actionName, currentRequestContextId,
                                                                                                      cancellationToken);

                    //TODO: current implementation supports generic/non-generic payload, consider using byte[] for all purpose
                    if (typeOfPayload != null)
                    {
                        payload = DeserializePayload((byte[])payload, typeOfPayload);
                    }

                    //main process logic
                    if (await ValidateDataAsync(actionName, payload, cancellationToken))
                    {
                        var result = await InternalProcessAsync(actionName, payload, cancellationToken);
                        await OnSuccessAsync(actionName, payload, result, cancellationToken);
                    }
                    else
                    {
                        await OnFailedAsync(actionName, payload,
                                            new ActorMessageValidationException(
                                                $"{CurrentActor} failed to validate its message of request {currentRequestContextId}"), cancellationToken);
                    }
                }
                catch (Exception e)
                {
                    await OnFailedAsync(actionName, payload, e, cancellationToken);

                    throw;
                }
                finally
                {
                    await ActorRequestPersistence.RemoveStateDataForRequestIdAsync(actionName, CurrentRequestContext.RequestId, cancellationToken);

                    //unregister reminder after process
                    await UnregisterReminderAsync(GetReminder(reminderName));
                }
            }
        }