예제 #1
0
        /// <summary>
        /// Internal constructor.
        /// </summary>
        /// <param name="parentWorkflow">The associated parent workflow.</param>
        /// <param name="methodName">
        /// Optionally identifies the target activity method by the name specified in
        /// the <c>[ActivityMethod]</c> attribute tagging the method.  Pass a <c>null</c>
        /// or empty string to specify the default method.
        /// </param>
        /// <param name="options">The activity options or <c>null</c>.</param>
        internal LocalActivityFutureStub(Workflow parentWorkflow, string methodName = null, LocalActivityOptions options = null)
        {
            Covenant.Requires <ArgumentNullException>(parentWorkflow != null, nameof(parentWorkflow));

            var activityInterface = typeof(TActivityInterface);

            TemporalHelper.ValidateActivityInterface(activityInterface);

            this.parentWorkflow = parentWorkflow;
            this.hasStarted     = false;
            this.targetMethod   = TemporalHelper.GetActivityTarget(activityInterface, methodName).TargetMethod;
            this.options        = LocalActivityOptions.Normalize(parentWorkflow.Client, options);
        }
예제 #2
0
        /// <summary>
        /// Internal constructor.
        /// </summary>
        /// <param name="parentWorkflow">The associated parent workflow.</param>
        /// <param name="methodName">
        /// Optionally identifies the target activity method by the name specified in
        /// the <c>[ActivityMethod]</c> attribute tagging the method.  Pass a <c>null</c>
        /// or empty string to target the default method.
        /// </param>
        /// <param name="options">The activity options or <c>null</c>.</param>
        internal ActivityFutureStub(Workflow parentWorkflow, string methodName = null, ActivityOptions options = null)
        {
            Covenant.Requires <ArgumentNullException>(parentWorkflow != null, nameof(parentWorkflow));

            var activityInterface = typeof(TActivityInterface);

            TemporalHelper.ValidateActivityInterface(activityInterface);

            this.parentWorkflow = parentWorkflow;
            this.client         = parentWorkflow.Client;
            this.hasStarted     = false;

            var activityTarget  = TemporalHelper.GetActivityTarget(activityInterface, methodName);
            var methodAttribute = activityTarget.MethodAttribute;

            this.activityTypeName = activityTarget.ActivityTypeName;
            this.targetMethod     = activityTarget.TargetMethod;
            this.options          = ActivityOptions.Normalize(client, options, typeof(TActivityInterface), activityTarget.TargetMethod);
        }
예제 #3
0
        //---------------------------------------------------------------------
        // Static members

        /// <summary>
        /// Normalizes the options passed by creating or cloning a new instance as
        /// required and filling unset properties using default client settings.
        /// </summary>
        /// <param name="client">The associated Temporal client.</param>
        /// <param name="options">The input options or <c>null</c>.</param>
        /// <param name="activityInterface">Optionally specifies the activity interface definition.</param>
        /// /// <param name="method">Optionally specifies the target workflow method.</param>
        /// <returns>The normalized options.</returns>
        /// <exception cref="ArgumentNullException">Thrown if a valid task queue is not specified.</exception>
        internal static ActivityOptions Normalize(TemporalClient client, ActivityOptions options, Type activityInterface = null, MethodInfo method = null)
        {
            Covenant.Requires <ArgumentNullException>(client != null, nameof(client));

            options = options ?? new ActivityOptions();

            ActivityInterfaceAttribute interfaceAttribute = null;
            ActivityMethodAttribute    methodAttribute    = null;

            if (activityInterface != null)
            {
                TemporalHelper.ValidateActivityInterface(activityInterface);

                interfaceAttribute = activityInterface.GetCustomAttribute <ActivityInterfaceAttribute>();
            }

            if (method != null)
            {
                methodAttribute = method.GetCustomAttribute <ActivityMethodAttribute>();
            }

            if (string.IsNullOrEmpty(options.Namespace))
            {
                if (!string.IsNullOrEmpty(methodAttribute?.Namespace))
                {
                    options.Namespace = methodAttribute.Namespace;
                }

                if (string.IsNullOrEmpty(options.Namespace) && !string.IsNullOrEmpty(interfaceAttribute?.Namespace))
                {
                    options.Namespace = interfaceAttribute.Namespace;
                }
            }

            if (string.IsNullOrEmpty(options.TaskQueue))
            {
                if (!string.IsNullOrEmpty(methodAttribute?.TaskQueue))
                {
                    options.TaskQueue = methodAttribute.TaskQueue;
                }

                if (string.IsNullOrEmpty(options.TaskQueue) && !string.IsNullOrEmpty(interfaceAttribute?.TaskQueue))
                {
                    options.TaskQueue = interfaceAttribute.TaskQueue;
                }
            }

            if (options.ScheduleToCloseTimeout <= TimeSpan.Zero)
            {
                if (methodAttribute != null && methodAttribute.ScheduleToCloseTimeoutSeconds > 0)
                {
                    options.ScheduleToCloseTimeout = TimeSpan.FromSeconds(methodAttribute.ScheduleToCloseTimeoutSeconds);
                }

                if (options.ScheduleToCloseTimeout <= TimeSpan.Zero)
                {
                    options.ScheduleToCloseTimeout = client.Settings.ActivityScheduleToCloseTimeout;
                }
            }

            if (options.ScheduleToStartTimeout <= TimeSpan.Zero)
            {
                if (methodAttribute != null && methodAttribute.ScheduleToStartTimeoutSeconds > 0)
                {
                    options.ScheduleToStartTimeout = TimeSpan.FromSeconds(methodAttribute.ScheduleToStartTimeoutSeconds);
                }

                if (options.ScheduleToStartTimeout <= TimeSpan.Zero)
                {
                    options.ScheduleToStartTimeout = client.Settings.ActivityScheduleToStartTimeout;
                }
            }

            if (options.StartToCloseTimeout <= TimeSpan.Zero)
            {
                if (methodAttribute != null && methodAttribute.StartToCloseTimeoutSeconds > 0)
                {
                    options.StartToCloseTimeout = TimeSpan.FromSeconds(methodAttribute.StartToCloseTimeoutSeconds);
                }

                if (options.StartToCloseTimeout <= TimeSpan.Zero)
                {
                    options.StartToCloseTimeout = client.Settings.ActivityStartToCloseTimeout;
                }
            }

            return(options);
        }
예제 #4
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();
            }
        }