-
Notifications
You must be signed in to change notification settings - Fork 148
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
New Update-with-Start API #2337
Conversation
2239e6d
to
f9e0ccb
Compare
.setCode(Status.INVALID_ARGUMENT.getCode().value()) | ||
.setMessage("INVALID_ARGUMENT: WorkflowStartDelay is not supported.") | ||
.build(), | ||
null); // update aborted |
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.
Moved this up to the other Start Operation validation.
f9e0ccb
to
18a33d6
Compare
if (startOp.getStub() == null) { | ||
throw new IllegalStateException( | ||
"WithStartWorkflowOperation was created with different WorkflowStub"); | ||
} |
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.
So this is worth discussing: the Start Operation's getResult
needs a class for the Workflow's result type to work. When using the typed stub to initialize it, it is inferred. When using the untyped, it is provided by the user explicitly.
However, when initialize it via the typed stub and using the untyped stub to run startUpdateWithStart, the type inference step was skipped and any call to startOp.getResult()
fails.
I don't see a way around this other than removing the getResult
shortcut entirely. Then this check can be safely removed.
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 think it is worth considering if the untyped stub startUpdateWithStart
API should even take a WithStartWorkflowOperation
?
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 guess startUpdateWithStart
is supposed to take a vargs
, and you can't have two varags
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.
Yup, @dandavison and I had that conversation and we were leaning towards using the WithStartWorkflowOperation
for the untyped startUpdateWithStart
API for these reasons:
(1) a signature like startUpdateWithStart(UpdateOptions<R> options, Object[] updateArgs, Object[] startArgs)
is potentially dangerous because users might mix up the order of the args (counterpoint: the existing signalWithStart
has the same problem)
(2) consistent use of the startOp
parameter across typed and untyped APIs
(3) allows convenience function getResult()
(1) is the main reason, (2) and (3) are minor reasons.
Having said that, neither of us - so far - felt very strongly about it.
18a33d6
to
cc8f73a
Compare
temporal-sdk/src/main/java/io/temporal/client/WorkflowInvocationHandler.java
Outdated
Show resolved
Hide resolved
cc8f73a
to
e1aedb4
Compare
if (options.getWorkflowIdConflictPolicy() == null) { | ||
throw new IllegalStateException( | ||
"Required parameter WorkflowIdConflictPolicy in WorkflowOptions is missing in WorkflowStub"); |
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.
Important change: we're making the WorkflowIdConflictPolicy
a required field for UwS across all SDKs.
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.
We could also consider an error message like
WorkflowIdConflictPolicy is required in WorkflowOptions for Update-With-Start
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.
Yeah +1 to this wording of the error
WorkflowClientCallsInterceptor.WorkflowUpdateWithStartOutput<R> output = | ||
workflowClientInvoker.updateWithStart(input); | ||
|
||
// gather outputs | ||
workflowExecution = output.getWorkflowStartOutput().getWorkflowExecution(); | ||
populateExecutionAfterStart(workflowExecution); |
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.
In other SDKs where we'll have a Future to obtain the workflow handle from the start operation, that future is immediately fulfilled once the run id is known. This can happen before the update wait stage has been reached.
I wonder if we want to do sth similar here. We could assign the workflow execution to the stub as soon as the run id is known. But it's not clear to me that it would do much since calling other functions on the stub are not waiting for the execution to be available.
I think we shouldn't do anything right now and re-consider based on feedback.
776f4ea
to
b645a0f
Compare
Summary of some parts of user-facing API in this PR:
So the untyped stub methods obtain the update name from the |
@dandavison yup, that's all correct!
That's true. I believe it's the same for the existing
|
@@ -857,300 +857,652 @@ static <R, A1, A2, A3, A4, A5, A6> WorkflowUpdateHandle<R> startUpdate( | |||
updateMethod, arg1, arg2, arg3, arg4, arg5, arg6, options); | |||
} | |||
|
|||
// TODO: UwS |
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.
[comment to be deleted]
static <R> WorkflowUpdateHandle<R> startUpdateWithStart( | ||
Proc updateMethod, | ||
@Nonnull UpdateOptions<R> options, | ||
@Nonnull WithStartWorkflowOperation<?> withStartOperation) { |
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 think we can name the parameter the straightforward/obvious name: startOperation
.
() -> updateMethod.apply(arg1, arg2, arg3, arg4, arg5, arg6), options, withStartOperation); | ||
} | ||
|
||
// TODO: UwS |
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.
[to be deleted]
if (options.getWorkflowIdConflictPolicy() == null) { | ||
throw new IllegalStateException( | ||
"Required parameter WorkflowIdConflictPolicy in WorkflowOptions is missing in WorkflowStub"); |
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.
We could also consider an error message like
WorkflowIdConflictPolicy is required in WorkflowOptions for Update-With-Start
static <A1, R> R executeUpdateWithStart( | ||
Func1<A1, R> updateMethod, | ||
A1 arg1, | ||
@Nonnull UpdateOptions<R> options, |
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.
It is a bit odd to use UpdateOptions
here since almost none of the options
here make any sense to set... The only option is makes sense to set is the update ID.
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 guess when we have durable on admitted support we will need to have a WaitStage
parameter for that...
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.
That's absolutely true. I'd support simplifying this executeUpdateWithStart(updateMethod, args ..., startOp)
. We can always add a new overload when we need it.
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 really want to avoid adding overloads to these methods if we can avoid it because the number of methods will explode with all the combinations for different numbers of parameters. I would support adding a TypedUpdateOptions
that only takes updateID
and WaitStage
and is used for all the update APIs on WorkflowClient
A general comment can we verify exceptions are consistent with |
void validateWaitForCompleted() { | ||
if (waitForStage != null && waitForStage != WorkflowUpdateStage.COMPLETED) { | ||
throw new IllegalArgumentException( | ||
"waitForStage must be unspecified or " + WorkflowUpdateStage.COMPLETED); | ||
} | ||
} |
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.
So I added this because I think users would rather ensure that the UwS call waits for "completed" when they call executeUpdateWithStart
, than have it be "accepted" (accidentally) and potentially impacting their experience (since an additional polling step might be needed).
This also seems better than silently setting it, but I don't feel strongly about this.
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.
Whatever we decide, the behavior for the "execute update" API(s) should do the same IMO.
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.
the behavior for the "execute update" API(s) should do the same IMO
The execute update APi in java is just calling the method on the stub hehe, but that uses COMPLETED
6c50c27
to
654c08c
Compare
@Quinn-With-Two-Ns My understanding is that the method invocations of |
Yes, but if the update is rejected or failed that is not an RPC issue and should not be surfaced as such. It should return an |
@Quinn-With-Two-Ns From what I can tell, UwS does the same, and returns a This includes when there's (a) server validation/rate limiting error (for start or update) or (b) the update never becomes durable and times out (client-side). Which seems to match the vanilla update behavior. |
@@ -233,21 +234,20 @@ public WorkflowStartOutput getWorkflowStartOutput() { | |||
|
|||
final class WorkflowUpdateWithStartInput<R> { | |||
private final WorkflowStartInput workflowStartInput; | |||
private final UpdateWithStartWorkflowOperation<R> updateOperation; | |||
private final StartUpdateInput<R> workflowUpdateInput; |
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.
@cretz pointed out in the Go SDK PR interceptors shouldn't reuse input/output from other interceptors, which I agree with , but the Java SDK has done that historically. I don't think we need to block the PR on this , but we should resist this before we make UwS stable in the Java SDK.
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 can file a ticket so we remember 👍
* | ||
* @param updateOptions options that will be used to configure and start a new update request | ||
* @param updateArgs update method arguments | ||
* @param starArgs workflow start arguments |
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.
typo, also in parameter names in code.
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.
LGTM
What was changed
Changed the Update-with-Start API to use a
WithStartWorkflowOperation
that expresses the workflow start.