-
Notifications
You must be signed in to change notification settings - Fork 248
Add support for setting ActivityID #3044
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 |
|---|---|---|
| @@ -0,0 +1,118 @@ | ||
| package io.temporal.internal.sync; | ||
|
|
||
| import io.temporal.workflow.ActivityInvocationOptions; | ||
| import io.temporal.workflow.Functions; | ||
| import io.temporal.workflow.Promise; | ||
| import java.util.Objects; | ||
|
|
||
| /** Applies options to one typed Activity proxy invocation. */ | ||
| final class ActivityInvocationInternal { | ||
|
|
||
| private static final ThreadLocal<State> invocation = new ThreadLocal<>(); | ||
| private static final ActivityInvocationOptions DEFAULT_OPTIONS = | ||
| ActivityInvocationOptions.newBuilder().build(); | ||
|
|
||
| private ActivityInvocationInternal() {} | ||
|
|
||
| static ActivityInvocationOptions getDefaultOptions() { | ||
| return DEFAULT_OPTIONS; | ||
| } | ||
|
|
||
| static <R> R invoke(ActivityInvocationOptions options, Functions.Func<R> invocationFunction) { | ||
| State state = startInvocation(options, false); | ||
| try { | ||
| R result = invocationFunction.apply(); | ||
| state.verifyConsumed(); | ||
| return result; | ||
| } finally { | ||
| invocation.remove(); | ||
| } | ||
| } | ||
|
|
||
| static void invoke(ActivityInvocationOptions options, Functions.Proc invocationFunction) { | ||
| State state = startInvocation(options, false); | ||
| try { | ||
| invocationFunction.apply(); | ||
| state.verifyConsumed(); | ||
| } finally { | ||
| invocation.remove(); | ||
| } | ||
| } | ||
|
|
||
| static <R> Promise<R> invokeAsync( | ||
| ActivityInvocationOptions options, Functions.Proc invocationFunction) { | ||
| State state = startInvocation(options, true); | ||
| try { | ||
| invocationFunction.apply(); | ||
| return state.getResult(); | ||
|
Comment on lines
+45
to
+47
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.
When the supplied function is a lambda that transforms the activity result, such as Useful? React with 👍 / 👎. |
||
| } finally { | ||
| invocation.remove(); | ||
| } | ||
| } | ||
|
|
||
| private static State startInvocation(ActivityInvocationOptions options, boolean async) { | ||
| if (invocation.get() != null) { | ||
| throw new IllegalStateException("Already invoking an Activity with invocation options"); | ||
| } | ||
|
|
||
| State state = new State(Objects.requireNonNull(options, "options"), async); | ||
| invocation.set(state); | ||
| return state; | ||
| } | ||
|
|
||
| static ActivityInvocationOptions consumeOptions() { | ||
| State state = invocation.get(); | ||
| if (state == null) { | ||
| return DEFAULT_OPTIONS; | ||
| } | ||
| if (state.consumed) { | ||
| throw new IllegalStateException("ActivityInvocationOptions can apply to only one invocation"); | ||
| } | ||
| state.consumed = true; | ||
| return state.options; | ||
| } | ||
|
|
||
| static <R> boolean captureResult(Promise<R> result) { | ||
| State state = invocation.get(); | ||
| if (state == null || !state.async) { | ||
| return false; | ||
| } | ||
| if (state.result != null) { | ||
| throw new IllegalStateException("ActivityInvocationOptions can apply to only one invocation"); | ||
| } | ||
| state.result = Objects.requireNonNull(result, "result"); | ||
| return true; | ||
| } | ||
|
|
||
| private static final class State { | ||
| private final ActivityInvocationOptions options; | ||
| private final boolean async; | ||
| private boolean consumed; | ||
| private Promise<?> result; | ||
|
|
||
| private State(ActivityInvocationOptions options, boolean async) { | ||
| this.options = options; | ||
| this.async = async; | ||
| } | ||
|
|
||
| private void verifyConsumed() { | ||
| if (!consumed) { | ||
| throw invalidInvocation(); | ||
| } | ||
| } | ||
|
|
||
| @SuppressWarnings("unchecked") | ||
| private <R> Promise<R> getResult() { | ||
| if (!consumed || result == null) { | ||
| throw invalidInvocation(); | ||
| } | ||
| return (Promise<R>) result; | ||
| } | ||
|
|
||
| private IllegalArgumentException invalidInvocation() { | ||
| return new IllegalArgumentException( | ||
| "activityMethod must invoke an Activity stub created through Workflow.newActivityStub " | ||
| + "or Workflow.newLocalActivityStub"); | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,11 +2,12 @@ | |
|
|
||
| import com.google.common.base.Defaults; | ||
| import io.temporal.failure.ActivityFailure; | ||
| import io.temporal.workflow.ActivityInvocationOptions; | ||
| import io.temporal.workflow.ActivityStub; | ||
| import io.temporal.workflow.Promise; | ||
| import java.lang.reflect.Type; | ||
|
|
||
| /** Supports calling activity by name and arguments without its strongly typed interface. */ | ||
| /** Supports calling an activity by name and arguments without its strongly typed interface. */ | ||
| abstract class ActivityStubBase implements ActivityStub { | ||
|
|
||
| @Override | ||
|
|
@@ -16,7 +17,46 @@ public <T> T execute(String activityName, Class<T> resultClass, Object... args) | |
|
|
||
| @Override | ||
| public <T> T execute(String activityName, Class<T> resultClass, Type resultType, Object... args) { | ||
| Promise<T> result = executeAsync(activityName, resultClass, resultType, args); | ||
| return getResult(executeAsync(activityName, resultClass, resultType, args), resultClass); | ||
| } | ||
|
|
||
| @Override | ||
| public <R> Promise<R> executeAsync(String activityName, Class<R> resultClass, Object... args) { | ||
| return executeAsync(activityName, resultClass, resultClass, args); | ||
| } | ||
|
|
||
| @Override | ||
| public <R> Promise<R> executeAsync( | ||
| String activityName, Class<R> resultClass, Type resultType, Object... args) { | ||
| return executeAsync( | ||
| activityName, | ||
| resultClass, | ||
| resultType, | ||
| ActivityInvocationInternal.getDefaultOptions(), | ||
| args); | ||
| } | ||
|
|
||
| @Override | ||
| public <R> R execute( | ||
| String activityName, | ||
| Class<R> resultClass, | ||
| ActivityInvocationOptions options, | ||
| Object... args) { | ||
| return execute(activityName, resultClass, resultClass, options, args); | ||
| } | ||
|
Comment on lines
+39
to
+46
Contributor
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. Nit: better to keep overloads of the same method next to each other. |
||
|
|
||
| @Override | ||
| public abstract <R> R execute( | ||
| String activityName, | ||
| Class<R> resultClass, | ||
| Type resultType, | ||
| ActivityInvocationOptions options, | ||
| Object... args); | ||
|
|
||
| protected <R> R getResult(Promise<R> result, Class<R> resultClass) { | ||
| if (ActivityInvocationInternal.captureResult(result)) { | ||
| return Defaults.defaultValue(resultClass); | ||
| } | ||
| if (AsyncInternal.isAsync()) { | ||
| AsyncInternal.setAsyncResult(result); | ||
| return Defaults.defaultValue(resultClass); | ||
|
|
@@ -33,11 +73,19 @@ public <T> T execute(String activityName, Class<T> resultClass, Type resultType, | |
| } | ||
|
|
||
| @Override | ||
| public <R> Promise<R> executeAsync(String activityName, Class<R> resultClass, Object... args) { | ||
| return executeAsync(activityName, resultClass, resultClass, args); | ||
| public <R> Promise<R> executeAsync( | ||
| String activityName, | ||
| Class<R> resultClass, | ||
| ActivityInvocationOptions options, | ||
| Object... args) { | ||
| return executeAsync(activityName, resultClass, resultClass, options, args); | ||
| } | ||
|
|
||
| @Override | ||
| public abstract <R> Promise<R> executeAsync( | ||
| String activityName, Class<R> resultClass, Type resultType, Object... args); | ||
| String activityName, | ||
| Class<R> resultClass, | ||
| Type resultType, | ||
| ActivityInvocationOptions options, | ||
| Object... args); | ||
| } | ||
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.
Nit: this should be a member of
ActivityInvocationOptionslike for other option types.