-
Notifications
You must be signed in to change notification settings - Fork 53
Added overloads for simplified func-based activity and orchestrator registration #589
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -4,16 +4,18 @@ | |||||
| namespace Microsoft.DurableTask; | ||||||
|
|
||||||
| /// <summary> | ||||||
| /// Indicates that the attributed class represents a durable task. | ||||||
| /// Indicates that the attributed class or method represents a durable task. | ||||||
| /// </summary> | ||||||
| /// <remarks> | ||||||
| /// This attribute is meant to be used on class definitions that derive from | ||||||
| /// <see cref="TaskOrchestrator{TInput, TOutput}"/>, <see cref="TaskActivity{TInput, TOutput}"/>, | ||||||
| /// or TaskEntity{TState} from the Microsoft.DurableTask.Entities namespace. | ||||||
| /// It can also be applied to methods used with <see cref="DurableTaskRegistry.AddOrchestratorFunc{TInput, TOutput}(System.Func{TaskOrchestrationContext, TInput, System.Threading.Tasks.Task{TOutput}})"/> | ||||||
| /// or similar overloads to specify a custom name for the orchestrator. | ||||||
|
||||||
| /// or similar overloads to specify a custom name for the orchestrator. | |
| /// or similar overloads to specify a custom name for the orchestrator or activity. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,6 +1,7 @@ | ||
| // Copyright (c) Microsoft Corporation. | ||
| // Licensed under the MIT License. | ||
|
|
||
| using System.Reflection; | ||
| using Microsoft.Extensions.DependencyInjection; | ||
|
|
||
| namespace Microsoft.DurableTask; | ||
|
|
@@ -21,7 +22,17 @@ TaskName and TActivity generic parameter | |
| ITaskActivity singleton | ||
| TaskName ITaskActivity singleton | ||
|
|
||
| by func/action: | ||
| by func/action (with explicit name): | ||
| Func{Context, Input, Task{Output}} | ||
| Func{Context, Input, Task} | ||
| Func{Context, Input, Output} | ||
| Func{Context, Task{Output}} | ||
| Func{Context, Task} | ||
| Func{Context, Output} | ||
| Action{Context, TInput} | ||
| Action{Context} | ||
|
|
||
| by func/action (name inferred from method or [DurableTask] attribute): | ||
| Func{Context, Input, Task{Output}} | ||
| Func{Context, Input, Task} | ||
| Func{Context, Input, Output} | ||
|
|
@@ -219,4 +230,167 @@ public DurableTaskRegistry AddActivityFunc(TaskName name, Action<TaskActivityCon | |
| return CompletedNullTask; | ||
| }); | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Registers an activity factory, where the implementation is <paramref name="activity" />. | ||
| /// The name is inferred from a <see cref="DurableTaskAttribute"/> on the method, or the method name. | ||
| /// </summary> | ||
| /// <typeparam name="TInput">The activity input type.</typeparam> | ||
| /// <typeparam name="TOutput">The activity output type.</typeparam> | ||
| /// <param name="activity">The activity implementation.</param> | ||
| /// <returns>The same registry, for call chaining.</returns> | ||
| /// <exception cref="ArgumentException"> | ||
| /// Thrown if the name cannot be inferred from the delegate. | ||
| /// </exception> | ||
| public DurableTaskRegistry AddActivityFunc<TInput, TOutput>( | ||
| Func<TaskActivityContext, TInput, Task<TOutput>> activity) | ||
| { | ||
| Check.NotNull(activity); | ||
| return this.AddActivityFunc(GetActivityNameFromDelegate(activity), activity); | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Registers an activity factory, where the implementation is <paramref name="activity" />. | ||
| /// The name is inferred from a <see cref="DurableTaskAttribute"/> on the method, or the method name. | ||
| /// </summary> | ||
| /// <typeparam name="TInput">The activity input type.</typeparam> | ||
| /// <typeparam name="TOutput">The activity output type.</typeparam> | ||
| /// <param name="activity">The activity implementation.</param> | ||
| /// <returns>The same registry, for call chaining.</returns> | ||
| /// <exception cref="ArgumentException"> | ||
| /// Thrown if the name cannot be inferred from the delegate. | ||
| /// </exception> | ||
| public DurableTaskRegistry AddActivityFunc<TInput, TOutput>( | ||
| Func<TaskActivityContext, TInput, TOutput> activity) | ||
| { | ||
| Check.NotNull(activity); | ||
| return this.AddActivityFunc(GetActivityNameFromDelegate(activity), activity); | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Registers an activity factory, where the implementation is <paramref name="activity" />. | ||
| /// The name is inferred from a <see cref="DurableTaskAttribute"/> on the method, or the method name. | ||
| /// </summary> | ||
| /// <typeparam name="TInput">The activity input type.</typeparam> | ||
| /// <param name="activity">The activity implementation.</param> | ||
| /// <returns>The same registry, for call chaining.</returns> | ||
| /// <exception cref="ArgumentException"> | ||
| /// Thrown if the name cannot be inferred from the delegate. | ||
| /// </exception> | ||
| public DurableTaskRegistry AddActivityFunc<TInput>(Func<TaskActivityContext, TInput, Task> activity) | ||
| { | ||
| Check.NotNull(activity); | ||
| return this.AddActivityFunc(GetActivityNameFromDelegate(activity), activity); | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Registers an activity factory, where the implementation is <paramref name="activity" />. | ||
| /// The name is inferred from a <see cref="DurableTaskAttribute"/> on the method, or the method name. | ||
| /// </summary> | ||
| /// <typeparam name="TOutput">The activity output type.</typeparam> | ||
| /// <param name="activity">The activity implementation.</param> | ||
| /// <returns>The same registry, for call chaining.</returns> | ||
| /// <exception cref="ArgumentException"> | ||
| /// Thrown if the name cannot be inferred from the delegate. | ||
| /// </exception> | ||
| public DurableTaskRegistry AddActivityFunc<TOutput>(Func<TaskActivityContext, Task<TOutput>> activity) | ||
| { | ||
| Check.NotNull(activity); | ||
| return this.AddActivityFunc(GetActivityNameFromDelegate(activity), activity); | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Registers an activity factory, where the implementation is <paramref name="activity" />. | ||
| /// The name is inferred from a <see cref="DurableTaskAttribute"/> on the method, or the method name. | ||
| /// </summary> | ||
| /// <param name="activity">The activity implementation.</param> | ||
| /// <returns>The same registry, for call chaining.</returns> | ||
| /// <exception cref="ArgumentException"> | ||
| /// Thrown if the name cannot be inferred from the delegate. | ||
| /// </exception> | ||
| public DurableTaskRegistry AddActivityFunc(Func<TaskActivityContext, Task> activity) | ||
| { | ||
| Check.NotNull(activity); | ||
| return this.AddActivityFunc(GetActivityNameFromDelegate(activity), activity); | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Registers an activity factory, where the implementation is <paramref name="activity" />. | ||
| /// The name is inferred from a <see cref="DurableTaskAttribute"/> on the method, or the method name. | ||
| /// </summary> | ||
| /// <typeparam name="TOutput">The activity output type.</typeparam> | ||
| /// <param name="activity">The activity implementation.</param> | ||
| /// <returns>The same registry, for call chaining.</returns> | ||
| /// <exception cref="ArgumentException"> | ||
| /// Thrown if the name cannot be inferred from the delegate. | ||
| /// </exception> | ||
| public DurableTaskRegistry AddActivityFunc<TOutput>(Func<TaskActivityContext, TOutput> activity) | ||
| { | ||
| Check.NotNull(activity); | ||
| return this.AddActivityFunc(GetActivityNameFromDelegate(activity), activity); | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Registers an activity factory, where the implementation is <paramref name="activity" />. | ||
| /// The name is inferred from a <see cref="DurableTaskAttribute"/> on the method, or the method name. | ||
| /// </summary> | ||
| /// <typeparam name="TInput">The activity input type.</typeparam> | ||
| /// <param name="activity">The activity implementation.</param> | ||
| /// <returns>The same registry, for call chaining.</returns> | ||
| /// <exception cref="ArgumentException"> | ||
| /// Thrown if the name cannot be inferred from the delegate. | ||
| /// </exception> | ||
| public DurableTaskRegistry AddActivityFunc<TInput>(Action<TaskActivityContext, TInput> activity) | ||
| { | ||
| Check.NotNull(activity); | ||
| return this.AddActivityFunc(GetActivityNameFromDelegate(activity), activity); | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Registers an activity factory, where the implementation is <paramref name="activity" />. | ||
| /// The name is inferred from a <see cref="DurableTaskAttribute"/> on the method, or the method name. | ||
| /// </summary> | ||
| /// <param name="activity">The activity implementation.</param> | ||
| /// <returns>The same registry, for call chaining.</returns> | ||
| /// <exception cref="ArgumentException"> | ||
| /// Thrown if the name cannot be inferred from the delegate. | ||
| /// </exception> | ||
| public DurableTaskRegistry AddActivityFunc(Action<TaskActivityContext> activity) | ||
| { | ||
| Check.NotNull(activity); | ||
| return this.AddActivityFunc(GetActivityNameFromDelegate(activity), activity); | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Gets the task name from a delegate by checking for a <see cref="DurableTaskAttribute"/> | ||
| /// or falling back to the method name. | ||
| /// </summary> | ||
| /// <param name="delegate">The delegate to extract the name from.</param> | ||
| /// <returns>The task name.</returns> | ||
| /// <exception cref="ArgumentException"> | ||
| /// Thrown if the name cannot be inferred from the delegate. | ||
| /// </exception> | ||
| static TaskName GetActivityNameFromDelegate(Delegate @delegate) | ||
| { | ||
| MethodInfo method = @delegate.Method; | ||
|
|
||
| // Check for DurableTaskAttribute on the method | ||
| DurableTaskAttribute? attribute = method.GetCustomAttribute<DurableTaskAttribute>(); | ||
| if (attribute?.Name.Name is not null and not "") | ||
| { | ||
| return attribute.Name; | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't really see how it's possible for |
||
| } | ||
|
|
||
| // Fall back to method name | ||
| string? methodName = method.Name; | ||
| if (string.IsNullOrEmpty(methodName) || methodName.StartsWith("<", StringComparison.Ordinal)) | ||
| { | ||
| throw new ArgumentException( | ||
| "Cannot infer activity name from the delegate. The delegate must either have a " + | ||
| "[DurableTask] attribute with a name, or be a named method (not a lambda or anonymous delegate).", | ||
| nameof(@delegate)); | ||
| } | ||
|
|
||
| return new TaskName(methodName); | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This change to include Directory.Packages.* appears unrelated to the PR's stated purpose of adding simplified func-based activity and orchestrator registration. This should be removed or moved to a separate PR if it's intended to be a general maintenance improvement.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm going to keep this in here since it's not worth creating a separate PR for.