From 0307814c784e83ae34dbacc40885efc22bda1544 Mon Sep 17 00:00:00 2001 From: Chad Retz Date: Tue, 25 Jul 2023 06:48:36 -0500 Subject: [PATCH] Remove activity definition cache --- .../Activities/ActivityDefinition.cs | 30 ++-------- .../Worker/WorkflowWorkerTests.cs | 56 +++++++++++++++++++ 2 files changed, 62 insertions(+), 24 deletions(-) diff --git a/src/Temporalio/Activities/ActivityDefinition.cs b/src/Temporalio/Activities/ActivityDefinition.cs index 5ba17eed..9b501d5a 100644 --- a/src/Temporalio/Activities/ActivityDefinition.cs +++ b/src/Temporalio/Activities/ActivityDefinition.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Reflection; @@ -13,8 +12,6 @@ namespace Temporalio.Activities /// public class ActivityDefinition { - private static readonly ConcurrentDictionary CachedDefinitions = new(); - private readonly Func invoker; private ActivityDefinition( @@ -65,16 +62,14 @@ private ActivityDefinition( /// must have set on it. /// /// Delegate to create definition from. - /// True if this should cache the result making successive invocations - /// for the same method quicker. /// Definition built from the delegate. - public static ActivityDefinition Create(Delegate del, bool cache = true) + public static ActivityDefinition Create(Delegate del) { if (del.Method == null) { throw new ArgumentException("Activities must have accessible methods"); } - return Create(del.Method, cache, del.DynamicInvoke); + return Create(del.Method, del.DynamicInvoke); } /// @@ -147,10 +142,9 @@ public static ActivityDefinition Create(MethodInfo method, FuncType with activity definitions. /// Instance to invoke the activity definitions on. Must be non-null /// if any activities are non-static. - /// True if each definition should be cached. /// Collection of activity definitions on the type. - public static IReadOnlyCollection CreateAll( - T? instance, bool cache = true) => CreateAll(typeof(T), instance, cache); + public static IReadOnlyCollection CreateAll(T? instance) => + CreateAll(typeof(T), instance); /// /// Create all applicable activity definitions for the given type. At least one activity @@ -159,10 +153,8 @@ public static IReadOnlyCollection CreateAll( /// Type with activity definitions. /// Instance to invoke the activity definitions on. Must be non-null /// if any activities are non-static. - /// True if each definition should be cached. /// Collection of activity definitions on the type. - public static IReadOnlyCollection CreateAll( - Type type, object? instance, bool cache = true) + public static IReadOnlyCollection CreateAll(Type type, object? instance) { var ret = new List(); foreach (var method in type.GetMethods( @@ -178,7 +170,7 @@ public static IReadOnlyCollection CreateAll( throw new InvalidOperationException( $"Instance not provided, but activity method {method} is non-static"); } - ret.Add(Create(method, cache, parameters => method.Invoke(instance, parameters))); + ret.Add(Create(method, parameters => method.Invoke(instance, parameters))); } if (ret.Count == 0) { @@ -242,16 +234,6 @@ internal static string NameFromMethodForCall(MethodInfo method) $"{method} cannot be used directly since it is a dynamic activity"); } - private static ActivityDefinition Create( - MethodInfo method, bool cache, Func invoker) - { - if (cache) - { - return CachedDefinitions.GetOrAdd(method, method => Create(method, false, invoker)); - } - return Create(method, invoker); - } - private static object?[] ParametersWithDefaults( ParameterInfo[] paramInfos, object?[] parameters) { diff --git a/tests/Temporalio.Tests/Worker/WorkflowWorkerTests.cs b/tests/Temporalio.Tests/Worker/WorkflowWorkerTests.cs index d1336a4c..d0a4bf7f 100644 --- a/tests/Temporalio.Tests/Worker/WorkflowWorkerTests.cs +++ b/tests/Temporalio.Tests/Worker/WorkflowWorkerTests.cs @@ -3012,6 +3012,62 @@ await ExecuteWorkerAsync( workerOptions); } + public class DuplicateActivities + { + private readonly string returnValue; + + public DuplicateActivities(string returnValue) => this.returnValue = returnValue; + + [Activity] + public string DoThing() => returnValue; + } + + [Workflow] + public class DuplicateActivityWorkflow + { + [WorkflowRun] + public async Task RunAsync(string taskQueue1, string taskQueue2) + { + return new[] + { + await Workflow.ExecuteActivityAsync( + (DuplicateActivities act) => act.DoThing(), + new() + { + TaskQueue = taskQueue1, + ScheduleToCloseTimeout = TimeSpan.FromHours(1), + }), + await Workflow.ExecuteActivityAsync( + (DuplicateActivities act) => act.DoThing(), + new() + { + TaskQueue = taskQueue2, + ScheduleToCloseTimeout = TimeSpan.FromHours(1), + }), + }; + } + } + + [Fact] + public async Task ExecuteWorkflowAsync_DuplicateActivity_DoesNotCacheInstance() + { + await ExecuteWorkerAsync( + async worker1 => + { + await ExecuteWorkerAsync( + async worker2 => + { + var ret = await Env.Client.ExecuteWorkflowAsync( + (DuplicateActivityWorkflow wf) => + wf.RunAsync(worker1.Options.TaskQueue!, worker2.Options.TaskQueue!), + new(id: $"workflow-{Guid.NewGuid()}", taskQueue: worker1.Options.TaskQueue!)); + Assert.Equal(new[] { "instance1", "instance2" }, ret); + }, + new TemporalWorkerOptions().AddAllActivities(new DuplicateActivities("instance2"))); + }, + new TemporalWorkerOptions().AddAllActivities(new DuplicateActivities("instance1"))); + } + private async Task ExecuteWorkerAsync( Func action, TemporalWorkerOptions? options = null,