-
Notifications
You must be signed in to change notification settings - Fork 81
Add WORKFLOW_EXECUTION_OPTIONS_UPDATED event type and remove FieldMask from WorkflowExecutionOptionsUpdated Event
#478
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
Conversation
cretz
left a comment
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, but I added a note where I think we need to at least clarify some simple rules for SDK on the field mask if we're going to start using field masks in history (sorry I did not see this earlier).
| message WorkflowExecutionOptionsUpdatedEventAttributes { | ||
| // Workflow Execution options that were sent in the UpdateWorkflowExecutionOptions request. | ||
| // Partial updates are accepted and controlled by update_mask. | ||
| temporal.api.workflow.v1.WorkflowExecutionOptions workflow_execution_options_update = 1; | ||
| temporal.api.workflow.v1.WorkflowExecutionOptions options = 1; | ||
|
|
||
| // Update mask that was sent in the UpdateWorkflowExecutionOptions request. | ||
| // Indicates which fields from `workflow_execution_options_for_update` were applied. | ||
| // Indicates which fields from `options` were applied. | ||
| google.protobuf.FieldMask update_mask = 2; | ||
| } |
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 didn't notice or I guess didn't say anything when this first appeared, but processing a field mask may be a bit rough to ask every SDK to do. Is it too much history to provide the full set of options always as they now sit? Or maybe we can just document this field mask here that 1) it will always be set with the updated fields (i.e. even if the user did not set it at RPC time because https://google.aip.dev/134#request-message does not require it), and 2) it will always be a fixed, non-nested field (i.e. never have dots or wildcards or any of 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.
hm yeah actually I was considering storing just the resulting options instead of the mask + request options.. I think the biggest thing would maybe be memo when/if we add memo to these? Do you know how big memo can be
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 actually would be slightly less repeated work in the server if I store the merged options only and no field..
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 don't have a strong preference. For practical reasons, I'd suggest to get rid of mask for now and punt the mask decision to a later time as and if more fields are added. This is so we can move forward with the versioning work in the very tight schedule that we have. (Right now, there is only one field in WorkflowExecutionOptions and this event has to change that only field.)
Correction: It would be hard to support old histories if we add the mask later. So we should add it now if we think it's a good thing. I do thing the mask is valuable because the UI (for example) can clearly show what options did change in that particular event.
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.
Do you guys think it's ok if I want to say that asterisk and empty field mask is not supported by my UpdateWorkflowExecutionOptions RPC (contrary to https://google.aip.dev/134#request-message guidelines), or should I implement the guidelines?
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.
@antlai-temporal and I are proposing this for the Go SDK:
["versioning_behavior_override"] -> invalid
["foo"] -> invalid
["*"] -> invalid
[] -> valid, means "PUT nothing, GET the full current options"
["VersioningBehaviorOverride"] -> valid
["VersioningBehaviorOverride.Behavior"] -> invalid
["VersioningBehaviorOverride.anything"] -> invalid
The RPC will differ slightly in that:
["versioning_behavior_override"] -> valid
["VersioningBehaviorOverride"] -> invalid
My reason for not supporting * is above, also I think there is not much benefit, since it would be rare that a user wanted to update memo AND priority AND versioning behavior AND timeouts all at once.
My reason for not supporting dot notation / partial updates, is that it becomes fraught when the struct being partially-updated can have field-combinations that are invalid, and maybe two callers are updating it and don't realize that one person just changed it. The structs are simple enough that I don't see a convincing use case for supporting partial struct updates and adding a lot of complexity.
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 an empty field to update everything is really dangerous.
We're on a thread about the history field here but I suppose we're also talking about the RPC.
I disagree. People need to be able to put the whole object by default and patch non-default. I believe this is what's happening with activity options field mask use and what https://google.aip.dev/134#request-message says to follow (where the concept of using field masks basically came from). If you want the SDK API to disallow this, that's fine, but people expect to be able to opt-in to partial updates with field masks, not out. The only thing that could maybe make sense is failing on empty field mask. But turning an update into a getter with an empty field mask does not make sense IMO and may end up making us inconsistent with ourselves and others expected use of field masks in gRPC.
proposing this for the Go SDK
This doesn't seem to be related to Go SDK
Also, the field names in the field mask need to match exactly what they are in proto and need to be the same for RPC and history (granted the latter should disallow special chars and such, but still should reference actual proto fields). So it should be versioning_behavior_override in both.
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.
Oh, I think we are interpreting this differently:
The field must be optional, and the service must treat an omitted field mask as an implied field mask equivalent to all fields that are populated (have a non-empty value).
My interpretation of that rule is that an "omitted field mask" is different from an "empty field mask". Where "omitted field mask" means update_mask == nil and "empty field mask" means update_mask.GetPaths() = []string{}
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.
Apologies for jumping between the history event question and the RPC question, I'm just in the middle of implementing the RPC and want to decide what to accept there.
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.
Makes sense, I was getting omitted vs empty mixed up too. IMO from an RPC POV, "omitted field mask" should be same as "full field mask", and "empty field mask" should probably be an error (there's no value in supporting this that I can think of). IMO from a history POV, the field mask should always be present and only have full field names with no wildcards or nesting (or we should decide that we don't want to take this field mask approach for history).
Also, if you wouldn't mind, can you get confirmation at least from @yiminc and @dnr that they are ok with this Google field mask structure inside history?
…t used' on WorkflowPropertiesModifiedExternallyEvent
| } | ||
|
|
||
| // Not used anywhere. Use case is replaced by WorkflowExecutionOptionsUpdatedEventAttributes | ||
| message WorkflowPropertiesModifiedExternallyEventAttributes { |
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 see we decided to not reuse this event and add your field to the bottom. Works for me (and I agree we can't really delete this), though would have also been ok just adding your field. Unsure if others have opinions here or not.
| // Indicates which fields from `workflow_execution_options_for_update` were applied. | ||
| google.protobuf.FieldMask update_mask = 2; | ||
| // Versioning override in the mutable state after event has been applied. | ||
| temporal.api.common.v1.VersioningBehaviorOverride versioning_override = 1; |
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 moving to common.v1.VersioningOverride as discussed. Do you want to include that change in this PR?
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.
Shahab has an open PR with that change, so I'm going to let it happen there to reduce churn / merge issues
WORKFLOW_EXECUTION_OPTIONS_UPDATED event type and remove FieldMask from WorkflowExecutionOptionsUpdated Event
WorkflowExecutionOptions, we will only store it in this event when it was upserted, so that we don't increase history size by storing memo on every OptionsUpdate. This works because Memo is never nil, only empty or populated, so a nil Memo in the event can mean "no change".ActivityPropertiesModifiedExternallyEventAttributesto indicate it was never used and is not intended to be used in the future.To implement the
UpdateWorkflowExecutionOptionsAPIBreaking changes
Server PR