Пример #1
0
        /// <summary>
        /// Internal constructor.
        /// </summary>
        /// <param name="parent">The parent activity implementation.</param>
        internal Activity(ActivityBase parent)
        {
            Covenant.Requires <ArgumentNullException>(parent != null, nameof(parent));

            this.parent = parent;
            this.Logger = LogManager.Default.GetLogger(sourceModule: Client.Settings.ClientIdentity, contextId: parent.ActivityTask?.WorkflowExecution?.RunId);
        }
Пример #2
0
        /// <summary>
        /// Registers an activity implementation with Cadence.
        /// </summary>
        /// <typeparam name="TActivity">The <see cref="ActivityBase"/> derived class implementing the activity.</typeparam>
        /// <param name="activityTypeName">
        /// Optionally specifies a custom activity type name that will be used
        /// for identifying the activity implementation in Cadence.  This defaults
        /// to the fully qualified <typeparamref name="TActivity"/> type name.
        /// </param>
        /// <param name="domain">Optionally overrides the default client domain.</param>
        /// <returns>The tracking <see cref="Task"/>.</returns>
        /// <exception cref="InvalidOperationException">Thrown if a different activity class has already been registered for <paramref name="activityTypeName"/>.</exception>
        /// <exception cref="ActivityWorkerStartedException">
        /// Thrown if an activity worker has already been started for the client.  You must
        /// register activity implementations before starting workers.
        /// </exception>
        /// <remarks>
        /// <note>
        /// Be sure to register all services you will be injecting into activities via
        /// <see cref="NeonHelper.ServiceContainer"/> before you call this as well as
        /// registering of your activity implementations before starting workers.
        /// </note>
        /// </remarks>
        public async Task RegisterActivityAsync <TActivity>(string activityTypeName = null, string domain = null)
            where TActivity : ActivityBase
        {
            await SyncContext.Clear;

            CadenceHelper.ValidateActivityImplementation(typeof(TActivity));
            CadenceHelper.ValidateActivityTypeName(activityTypeName);
            EnsureNotDisposed();

            if (activityWorkerStarted)
            {
                throw new ActivityWorkerStartedException();
            }

            var activityType = typeof(TActivity);

            if (string.IsNullOrEmpty(activityTypeName))
            {
                activityTypeName = CadenceHelper.GetActivityTypeName(activityType, activityType.GetCustomAttribute <ActivityAttribute>());
            }

            await ActivityBase.RegisterAsync(this, activityType, activityTypeName, ResolveDomain(domain));

            lock (registeredActivityTypes)
            {
                registeredActivityTypes.Add(CadenceHelper.GetActivityInterface(typeof(TActivity)));
            }
        }
Пример #3
0
        /// <summary>
        /// Scans the assembly passed looking for activity implementations derived from
        /// <see cref="ActivityBase"/> and tagged by <see cref="ActivityAttribute"/> and
        /// registers them with Cadence.
        /// </summary>
        /// <param name="assembly">The target assembly.</param>
        /// <param name="domain">Optionally overrides the default client domain.</param>
        /// <returns>The tracking <see cref="Task"/>.</returns>
        /// <exception cref="TypeLoadException">
        /// Thrown for types tagged by <see cref="ActivityAttribute"/> that are not
        /// derived from <see cref="ActivityBase"/>.
        /// </exception>
        /// <exception cref="InvalidOperationException">Thrown if one of the tagged classes conflict with an existing registration.</exception>
        /// <exception cref="ActivityWorkerStartedException">
        /// Thrown if an activity worker has already been started for the client.  You must
        /// register activity implementations before starting workers.
        /// </exception>
        /// <remarks>
        /// <note>
        /// Be sure to register all services you will be injecting into activities via
        /// <see cref="NeonHelper.ServiceContainer"/> before you call this as well as
        /// registering of your activity implementations before starting workers.
        /// </note>
        /// </remarks>
        public async Task RegisterAssemblyActivitiesAsync(Assembly assembly, string domain = null)
        {
            await SyncContext.Clear;

            Covenant.Requires <ArgumentNullException>(assembly != null, nameof(assembly));
            EnsureNotDisposed();

            if (activityWorkerStarted)
            {
                throw new ActivityWorkerStartedException();
            }

            foreach (var type in assembly.GetTypes().Where(type => type.IsClass))
            {
                var activityAttribute = type.GetCustomAttribute <ActivityAttribute>();

                if (activityAttribute != null && activityAttribute.AutoRegister)
                {
                    var activityTypeName = CadenceHelper.GetActivityTypeName(type, activityAttribute);

                    await ActivityBase.RegisterAsync(this, type, activityTypeName, ResolveDomain(domain));

                    lock (registeredActivityTypes)
                    {
                        registeredActivityTypes.Add(CadenceHelper.GetActivityInterface(type));
                    }
                }
            }
        }
Пример #4
0
        //---------------------------------------------------------------------
        // Cadence activity related operations.

        /// <summary>
        /// Registers an activity implementation with Cadence.
        /// </summary>
        /// <typeparam name="TActivity">The <see cref="IActivityBase"/> derived class implementing the activity.</typeparam>
        /// <param name="activityTypeName">
        /// Optionally specifies a custom activity type name that will be used
        /// for identifying the activity implementation in Cadence.  This defaults
        /// to the fully qualified <typeparamref name="TActivity"/> type name.
        /// </param>
        /// <returns>The tracking <see cref="Task"/>.</returns>
        /// <exception cref="InvalidOperationException">Thrown if a different activity class has already been registered for <paramref name="activityTypeName"/>.</exception>
        /// <exception cref="CadenceActivityWorkerStartedException">
        /// Thrown if an activity worker has already been started for the client.  You must
        /// register activity implementations before starting workers.
        /// </exception>
        /// <remarks>
        /// <note>
        /// Be sure to register all of your activity implementations before starting a workflow worker.
        /// </note>
        /// </remarks>
        public async Task RegisterActivityAsync <TActivity>(string activityTypeName = null)
            where TActivity : ActivityBase
        {
            CadenceHelper.ValidateActivityImplementation(typeof(TActivity));

            if (string.IsNullOrEmpty(activityTypeName))
            {
                activityTypeName = activityTypeName ?? typeof(TActivity).FullName;
            }

            if (activityWorkerStarted)
            {
                throw new CadenceActivityWorkerStartedException();
            }

            if (!ActivityBase.Register(this, typeof(TActivity), activityTypeName))
            {
                var reply = (ActivityRegisterReply) await CallProxyAsync(
                    new ActivityRegisterRequest()
                {
                    Name = activityTypeName
                });

                reply.ThrowOnError();
            }
        }
Пример #5
0
        /// <summary>
        /// Handles workflow local activity invocations.
        /// </summary>
        /// <param name="client">The client the request was received from.</param>
        /// <param name="request">The request message.</param>
        /// <returns>The reply message.</returns>
        internal static async Task<ActivityInvokeLocalReply> OnInvokeLocalActivity(CadenceClient client, ActivityInvokeLocalRequest request)
        {
            Covenant.Requires<ArgumentNullException>(request != null, nameof(request));

            try
            {
                WorkflowBase.CallContext.Value = WorkflowCallContext.Activity;

                var workflow = GetWorkflow(client, request.ContextId);

                if (workflow != null)
                {
                    LocalActivityAction activityAction;

                    lock (syncLock)
                    {
                        if (!workflow.Workflow.IdToLocalActivityAction.TryGetValue(request.ActivityTypeId, out activityAction))
                        {
                            return new ActivityInvokeLocalReply()
                            {
                                Error = new EntityNotExistsException($"Activity type does not exist for [activityTypeId={request.ActivityTypeId}].").ToCadenceError()
                            };
                        }
                    }

                    var workerArgs = new WorkerArgs() { Client = client, ContextId = request.ActivityContextId };
                    var activity   = ActivityBase.Create(client, activityAction, null);
                    var result     = await activity.OnInvokeAsync(client, request.Args);

                    return new ActivityInvokeLocalReply()
                    {
                        Result = result
                    };
                }
                else
                {
                    return new ActivityInvokeLocalReply()
                    {
                        Error = new EntityNotExistsException($"Workflow with [contextID={request.ContextId}] does not exist.").ToCadenceError()
                    };
                }
            }
            catch (Exception e)
            {
                log.LogError(e);

                return new ActivityInvokeLocalReply()
                {
                    Error = new CadenceError(e)
                };
            }
            finally
            {
                WorkflowBase.CallContext.Value = WorkflowCallContext.None;
            }
        }
Пример #6
0
        /// <summary>
        /// Scans the assembly passed looking for activity implementations derived from
        /// <see cref="IActivityBase"/> and tagged by <see cref="ActivityAttribute"/> and
        /// registers them with Cadence.
        /// </summary>
        /// <param name="assembly">The target assembly.</param>
        /// <returns>The tracking <see cref="Task"/>.</returns>
        /// <exception cref="TypeLoadException">
        /// Thrown for types tagged by <see cref="ActivityAttribute"/> that are not
        /// derived from <see cref="IActivityBase"/>.
        /// </exception>
        /// <exception cref="InvalidOperationException">Thrown if one of the tagged classes conflict with an existing registration.</exception>
        /// <exception cref="CadenceActivityWorkerStartedException">
        /// Thrown if an activity worker has already been started for the client.  You must
        /// register activity implementations before starting workers.
        /// </exception>
        /// <remarks>
        /// <note>
        /// Be sure to register all of your activity implementations before starting a workflow worker.
        /// </note>
        /// </remarks>
        public async Task RegisterAssemblyActivitiesAsync(Assembly assembly)
        {
            Covenant.Requires <ArgumentNullException>(assembly != null);

            if (activityWorkerStarted)
            {
                throw new CadenceActivityWorkerStartedException();
            }

            foreach (var type in assembly.GetTypes())
            {
                var activityAttribute = type.GetCustomAttribute <ActivityAttribute>();

                if (activityAttribute != null)
                {
                    if (type.Implements <IActivityBase>())
                    {
                        if (activityAttribute.AutoRegister)
                        {
                            var activityTypeName = activityAttribute.TypeName ?? type.FullName;

                            if (!ActivityBase.Register(this, type, activityTypeName))
                            {
                                var reply = (ActivityRegisterReply) await CallProxyAsync(
                                    new ActivityRegisterRequest()
                                {
                                    Name = activityTypeName
                                });

                                reply.ThrowOnError();
                            }
                        }
                    }
                    else
                    {
                        throw new TypeLoadException($"Type [{type.FullName}] is tagged by [{nameof(ActivityAttribute)}] but is not derived from [{nameof(IActivityBase)}].");
                    }
                }
            }
        }
Пример #7
0
        /// <summary>
        /// Internal constructor.
        /// </summary>
        /// <param name="activity">The parent activity implementation.</param>
        internal Activity(ActivityBase activity)
        {
            Covenant.Requires <ArgumentNullException>(activity != null);

            this.activity = activity;
        }