-
Notifications
You must be signed in to change notification settings - Fork 76
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
Workflow Update #400
Workflow Update #400
Conversation
"Dynamic updates do not support a vararg third param, use Sequence[RawValue]", | ||
) | ||
setattr(fn, "__temporal_update_definition", defn) | ||
setattr(fn, "validator", partial(_update_validator, defn)) |
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.
Probably this should return a class rather than doing this, so IDE docstring/hints work on validator
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 this is quite nice now - we might consider changing the others to the extent it's compatible. Fewer magic attributes.
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 is still nicer I think, but avoids using a class decorator because of unlimited type hell.
488fa66
to
1da053f
Compare
1da053f
to
713c847
Compare
818f6f2
to
533b9f7
Compare
6f8121c
to
5daec88
Compare
dc23266
to
3a9dc2c
Compare
9ddd357
to
188bf97
Compare
@@ -515,6 +515,12 @@ class GreetingWorkflow: | |||
@workflow.query | |||
def current_greeting(self) -> str: | |||
return self._current_greeting | |||
|
|||
@workflow.update | |||
def set_and_get_greeting(self, greeting: str) -> str: |
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.
Hrmm, I wonder if just altering update_salutation
to be an update that return the previous salutation part would be enough. Also, I wonder if calling this update_greeting
is descriptive enough. I don't think it matters much. But I will take the approach of return-old-thing in the .NET PR.
* `@workflow.update` - Defines a method as an update | ||
* May both accept as input and return a value | ||
* May be `async` or non-`async` | ||
* May mutate workflow state, and make calls to other workflow APIs like starting activities, etc. |
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.
* May mutate workflow state, and make calls to other workflow APIs like starting activities, etc. | |
* May mutate workflow state, make calls to other workflow APIs like starting activities, etc. |
(pedantic, can ignore)
async def run_update() -> None: | ||
command = self._add_command() | ||
command.update_response.protocol_instance_id = job.protocol_instance_id | ||
try: |
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 might be helpful to place this method next to _run_top_level_workflow_function
, or have them mention each other in a comment, for people seeking to understand our error handling behavior in the different handlers and in the main workflow code. (I'm assuming that for now we don't see any attractive way for them to share implementation.)
Saw some things resolved/addressed but maybe not pushed yet pending core update or something. Will wait for push before re-reviewing. |
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, mostly just naming of tracing spans and interceptor classes and similar small things. Oh and we probably want the update handle to have its return type generic/typed.
# the specific named update - we shouldn't fall back to the dynamic validator | ||
# for some defined, named update which doesn't have a defined validator. | ||
handler = self._instance.workflow_get_update_validator(input.update) | ||
# Validator may not be defined |
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 theory this should not longer happen anymore since you check before interceptor, but fine to check again in here (just in case they did something wonky like unset it in an outer interceptor)
temporalio/client.py
Outdated
outcome = self._known_result | ||
return await _update_outcome_to_result( | ||
outcome, |
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'd like to change the _known_result
variable name to _known_outcome
. That name matches its type, and it's an important distinction since the outcome can be Failed
, in which case there isn't a "result" in the sense that that word is used everywhere else.
(I'm not making this comment during a code review -- I'm making it after getting briefly confused by this issue while reading the Python implementation in the course of Typescript implementation, so a data point exists that this is a real confusion risk.)
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.
.NET did call it KnownOutcome
but I don't think it matters much since this is private API. It seems ok to me to name something "known result" if it's a "known" thing for the "result" method later, but I'm ok changing it to known_outcome too.
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.
Renamed
temporalio/client.py
Outdated
TimeoutError: The specified timeout was reached when waiting for the update result. | ||
RPCError: Update result could not be fetched for some other reason. | ||
""" | ||
if self._known_result is not None: |
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: I'd prefer to write this as if self._known_result
. The types establish that bool(self._known_result)
iff the response has an Outcome
.
b1a5ee7
to
ba4bda7
Compare
ba4bda7
to
6670ee5
Compare
*, | ||
args: Sequence[Any] = [], | ||
id: Optional[str] = None, | ||
wait_for_stage: temporalio.api.enums.v1.UpdateWorkflowExecutionLifecycleStage.ValueType = temporalio.api.enums.v1.UpdateWorkflowExecutionLifecycleStage.UPDATE_WORKFLOW_EXECUTION_LIFECYCLE_STAGE_ADMITTED, |
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 understand why you defaulted this to ADMITTED
(it's what's most natural when asking for a handle) and I know the API is not exposed to users, but ADMITTED
is completely unimplemented server-side and there is no agreed plan for how it would be implemented yet, and no timeline for implementing it, so maybe it's a bit odd for it to be in the SDK codebase? Maybe it should be a required positional arg.
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!
DRAFT - Still need to finish async updates & add more tests
What was changed
Implement Workflow Update
Why?
Duh
Checklist
Closes [Python] Workflow update support #336
How was this tested:
Added tests
Any docs updates needed?
Yup