Example #1
0
        /// <summary>
        /// Registers an activity implementation with Temporal.
        /// </summary>
        /// <typeparam name="TActivity">The <see cref="ActivityBase"/> derived class implementing the activity.</typeparam>
        /// <param name="disableDuplicateCheck">Disable checks for duplicate activity registrations.</param>
        /// <returns>The tracking <see cref="Task"/>.</returns>
        /// <exception cref="InvalidOperationException">
        /// Thrown if the worker has already been started.  You must register workflow
        /// and activity implementations before starting a worker.
        /// </exception>
        /// <exception cref="RegistrationException">Thrown when there's a problem with the registration.</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 a worker.
        /// </note>
        /// </remarks>
        public async Task RegisterActivityAsync <TActivity>(bool disableDuplicateCheck = false)
            where TActivity : ActivityBase
        {
            await SyncContext.Clear;

            TemporalHelper.ValidateActivityImplementation(typeof(TActivity));
            EnsureNotDisposed();
            EnsureCanRegister();

            lock (registeredActivityTypes)
            {
                var activityType = typeof(TActivity);

                if (registeredActivityTypes.Contains(activityType))
                {
                    if (disableDuplicateCheck)
                    {
                        return;
                    }
                    else
                    {
                        throw new RegistrationException($"Activity implementation [{typeof(TActivity).FullName}] has already been registered.");
                    }
                }

                registeredActivityTypes.Add(activityType);
            }
        }
Example #2
0
        /// <summary>
        /// Called internally to initialize the activity.
        /// </summary>
        /// <param name="worker">The worker hosting the activity.</param>
        /// <param name="activityType">Specifies the target activity type.</param>
        /// <param name="activityMethod">Specifies the target activity method.</param>
        /// <param name="dataConverter">Specifies the data converter to be used for parameter and result serilization.</param>
        /// <param name="contextId">The activity's context ID.</param>
        internal void Initialize(Worker worker, Type activityType, MethodInfo activityMethod, IDataConverter dataConverter, long contextId)
        {
            Covenant.Requires <ArgumentNullException>(worker != null, nameof(worker));
            Covenant.Requires <ArgumentNullException>(activityType != null, nameof(activityType));
            Covenant.Requires <ArgumentNullException>(activityMethod != null, nameof(activityMethod));
            Covenant.Requires <ArgumentNullException>(dataConverter != null, nameof(dataConverter));
            TemporalHelper.ValidateActivityImplementation(activityType);

            this.worker                  = worker;
            this.Client                  = worker.Client;
            this.Activity                = new Activity(this);
            this.activityType            = activityType;
            this.activityMethod          = activityMethod;
            this.dataConverter           = dataConverter;
            this.ContextId               = contextId;
            this.CancellationTokenSource = new CancellationTokenSource();
            this.CancellationToken       = CancellationTokenSource.Token;
            this.logger                  = LogManager.Default.GetLogger(module: activityType.FullName);
        }
Example #3
0
        /// <summary>
        /// Registers an activity implementation with the temporal-proxy.
        /// </summary>
        /// <param name="activityType">The activity implementation type.</param>
        /// <exception cref="RegistrationException">Thrown when there's a problem with the registration.</exception>
        private async Task RegisterActivityImplementationAsync(Type activityType)
        {
            await SyncContext.Clear;

            TemporalHelper.ValidateActivityImplementation(activityType);

            var interfaceType = TemporalHelper.GetActivityInterface(activityType);

            TemporalHelper.ValidateActivityInterface(interfaceType);

            // We need to register each activity method that implements an activity interface method
            // with the same signature that that was tagged by [ActivityMethod].
            //
            // First, we'll create a dictionary that maps method signatures from any inherited
            // interfaces that are tagged by [ActivityMethod] to the attribute.

            var methodSignatureToAttribute = new Dictionary <string, ActivityMethodAttribute>();

            foreach (var method in interfaceType.GetMethods(BindingFlags.Public | BindingFlags.Instance))
            {
                var activityMethodAttribute = method.GetCustomAttribute <ActivityMethodAttribute>();

                if (activityMethodAttribute == null)
                {
                    continue;
                }

                var signature = method.ToString();

                if (methodSignatureToAttribute.ContainsKey(signature))
                {
                    throw new NotSupportedException($"Activity type [{activityType.FullName}] cannot implement the [{signature}] method from two different interfaces.");
                }

                methodSignatureToAttribute.Add(signature, activityMethodAttribute);
            }

            // Next, we need to register the activity methods that implement the
            // activity interface.

            foreach (var method in activityType.GetMethods())
            {
                if (!methodSignatureToAttribute.TryGetValue(method.ToString(), out var activityMethodAttribute))
                {
                    continue;
                }

                var activityTarget = TemporalHelper.GetActivityTarget(interfaceType, activityMethodAttribute.Name);

                lock (nameToActivityRegistration)
                {
                    if (nameToActivityRegistration.TryGetValue(activityTarget.ActivityTypeName, out var registration))
                    {
                        if (!object.ReferenceEquals(registration.ActivityType, registration.ActivityType))
                        {
                            throw new InvalidOperationException($"Conflicting activity type registration: Activity type [{activityType.FullName}] is already registered for activity type name [{activityTarget.ActivityTypeName}].");
                        }
                    }
                    else
                    {
                        nameToActivityRegistration[activityTarget.ActivityTypeName] =
                            new ActivityRegistration()
                        {
                            ActivityType   = activityType,
                            ActivityMethod = method,
                            ActivityMethodParameterTypes = method.GetParameterTypes()
                        };
                    }
                }

                var reply = (ActivityRegisterReply)await Client.CallProxyAsync(
                    new ActivityRegisterRequest()
                {
                    WorkerId = WorkerId,
                    Name     = activityTarget.ActivityTypeName,
                });

                reply.ThrowOnError();
            }
        }