Skip to content
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

Add OnConflictOptions to StartWorkflowExecutionRequest #510

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

rodrigozhou
Copy link
Contributor

READ BEFORE MERGING: All PRs require approval by both Server AND SDK teams before merging! This is why the number of required approvals is "2" and not "1"--two reviewers from the same team is NOT sufficient. If your PR is not approved by someone in BOTH teams, it may be summarily reverted.

What changed?
Add OnConflictOptions to StartWorkflowExecutionRequest

Why?
When the workflow id conflict policy is USE_EXISTING, OnConflictOptions add the ability to change the existing running workflow.

Breaking changes

Server PR
temporalio/temporal#7080

@rodrigozhou rodrigozhou requested review from bergundy and cretz January 14, 2025 19:09
@rodrigozhou rodrigozhou requested review from a team as code owners January 14, 2025 19:09
Copy link
Member

@bergundy bergundy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved with a couple of small comments.

temporal/api/history/v1/message.proto Outdated Show resolved Hide resolved

// When StartWorkflowExecution uses the WORKFLOW_ID_CONFLICT_POLICY_USE_EXISTING conflict policy and
// there is already an existing running workflow, OnConflictOptions defines actions to be taken on
// the existing running workflow.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd mention that we plan to add options here as needed.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm adding explicitly the behaviors we want to implement at first already, so I think no need to update comment.

Comment on lines 210 to 211
// conflict policy is used. If set to non-nil empty object, it will attach the completion
// callbacks to the existing running workflow. If not set (ie., nil value), it won't do anything
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If set to non-nil empty object, it will attach the completion callbacks to the existing running workflow

Why not make this an explicit option on the object? The code has to opt-in to this anyways by providing a non-null object, might as well opt-in to which things they want to attach. It seems strange to have some that are attached by default and maybe later some that are affected by options.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, I'm ok with being explicit. cc: @bergundy

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've added attach_completion_callbacks and attach_links. I'm not adding attach_request_id because request id is used for deduping, so I think it make sense that if OnConflictOptions is set, then we need to always attach the request id to dedup the request, and not redo work.

Copy link
Member

@cretz cretz Jan 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it make sense that if OnConflictOptions is set, then we need to always attach the request id to dedup the request, and not redo work

Not following the request ID thing. I do not think the presence or absence of this field should change the behavior (i.e. an empty value and a null value should behave the same). It is confusing to just have an empty object do something different.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The purpose of the request ID is to dedup the request in case the client retries the same request, but the server already processed the request.

If the OnConflictOptions field is not nil, then likely the user wants to do something with the existing running workflow (eg: add callbacks). So, we want to be able to dedup this request in case the client retries the request, ie., we need to attach the request ID to the workflow.

Copy link
Member

@cretz cretz Jan 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the OnConflictOptions field is not nil, then likely the user wants to do something with the existing running workflow (eg: add callbacks).

You don't know how the options will grow or be used in the future. IMO we need to require the user explicitly say they want to attach request ID or we need to always attach the request ID on use-existing. To sometimes do it based on null-ness of some options message is folly IMO. In many langs we may always populate this option and just not set any fields (or at least the code for building the proto shouldn't have to understand the advanced nuances of setting an empty proto message vs no message).

// When StartWorkflowExecution uses the WORKFLOW_ID_CONFLICT_POLICY_USE_EXISTING conflict policy and
// there is already an existing running workflow, OnConflictOptions defines actions to be taken on
// the existing running workflow.
message OnConflictOptions {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will this message be used anywhere else except start workflow?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe in schedules?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no ID conflict policy in schedules (by intention as I understand it due to how schedules set IDs)

// conflict policy is used. If set to non-nil empty object, it will attach the completion
// callbacks to the existing running workflow. If not set (ie., nil value), it won't do anything
// to the existing running workflow.
temporal.api.workflow.v1.OnConflictOptions on_conflict_options = 26;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this needed for signal-with-start?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think so, because for signal with start we're thinking that you care more about the signal than the start and we don't plan on attaching the Nexus operation to the workflow's lifecycle.

Copy link
Member

@cretz cretz Jan 14, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But this is a general purpose concept not specific to Nexus. In general everywhere a conflict policy is applied it'd make sense to apply conflict options IMO.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the case of signal with start, the goal is to signal the workflow if it's already running, not update it.
Supporting OnConflictOptions in this case would mean that the behavior of signal with start would be to update and signal the workflow? Would this make sense?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the general idea of this being paired with a conflict policy makes sense for consistency reasons. I think your question could be rephrased as "does conflict policy make sense on signal with start", but since it was decided it does however that was decided, I think these options should go alongside them.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see a use case for attaching callbacks and links to a running workflow on signal-with-start.
We plan to attach a link on the WorkflowExecutionSignaled event (and probably on the WorkflowExecutionStarted event if the current request started a new workflow). But we do not have plans to attach callbacks on signal-with-start.
I'd rather only add fields that we plan on using.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On conflict options is about what do to on conflict. Whether a use case exists for these first couple of options I don't think affects the fact that everywhere a conflict policy is applied, its conflict options should apply.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would still rather add this later. We don't plan on adding server support for this quite yet.

@rodrigozhou rodrigozhou force-pushed the rodrigozhou/conflict-options branch from 865e27d to 410f8e0 Compare January 15, 2025 01:40
@rodrigozhou rodrigozhou requested review from bergundy and cretz January 15, 2025 01:41
@rodrigozhou rodrigozhou force-pushed the rodrigozhou/conflict-options branch from 410f8e0 to 7a221d7 Compare January 15, 2025 01:48
Comment on lines +448 to +449
bool attach_completion_callbacks = 1;
bool attach_links = 2;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
bool attach_completion_callbacks = 1;
bool attach_links = 2;
bool append_completion_callbacks = 1;
bool append_links = 2;

I think this may be clearer terminology (assuming it is actually "appending")

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This works for me although I prefer the term attach over append but don't have a strong opinion on that.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For callbacks, "append" makes sense since we adding to the workflow execution.
But for links, this is set in the history event, it's not "appending" an existing list/object.
I'm ok with changing for callbacks, but I'd leave "attach" for links.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think what each of these do to existing values may need to be documented here because it is clearly confusing. What does "attach" mean for links? If links are set in the history event and immutable, then where in history are these new ones set? Or are there now two kinds of links, start links and post-start links, and they manifest in different ways?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree we should document these options.

The link would essentially be linked to the new event but conceptually they're considered attached to the workflow.

flowchart LR
    CallerWorkflowA --> HandlerWorkflow
    CallerWorkflowB --> HandlerWorkflow
Loading

The callback is added to the list of completion callbacks.

Comment on lines 210 to 211
// conflict policy is used. If set to non-nil empty object, it will attach the completion
// callbacks to the existing running workflow. If not set (ie., nil value), it won't do anything
Copy link
Member

@cretz cretz Jan 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it make sense that if OnConflictOptions is set, then we need to always attach the request id to dedup the request, and not redo work

Not following the request ID thing. I do not think the presence or absence of this field should change the behavior (i.e. an empty value and a null value should behave the same). It is confusing to just have an empty object do something different.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants