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

EDU-3236: Update-with-Start #3120

Draft
wants to merge 21 commits into
base: main
Choose a base branch
from

Conversation

stephanos
Copy link
Contributor

@stephanos stephanos commented Oct 2, 2024

What does this PR do?

Adds documentation for the Update-with-Start feature as well as its Go SDK usage.

@stephanos stephanos force-pushed the update-with-start branch 2 times, most recently from 3cada6c to c63df10 Compare October 2, 2024 17:42
@stephanos stephanos force-pushed the update-with-start branch 5 times, most recently from 59a5b3a to 2e44524 Compare October 27, 2024 18:25
docs/develop/go/message-passing.mdx Outdated Show resolved Hide resolved
docs/encyclopedia/application-message-passing.mdx Outdated Show resolved Hide resolved
docs/encyclopedia/application-message-passing.mdx Outdated Show resolved Hide resolved
docs/encyclopedia/application-message-passing.mdx Outdated Show resolved Hide resolved
docs/encyclopedia/application-message-passing.mdx Outdated Show resolved Hide resolved
docs/develop/go/message-passing.mdx Outdated Show resolved Hide resolved
@fairlydurable fairlydurable changed the title Update-with-Start EDU-3236: Update-with-Start Nov 12, 2024
@@ -300,7 +300,7 @@ If there's a Workflow running with the given Workflow Id, it will be signaled. I

Use the [`Client.SignalWithStartWorkflow`](https://pkg.go.dev/go.temporal.io/sdk/client#Client.SignalWithStartWorkflow) API to start a Workflow Execution (if not already running) and pass it the Signal at the same time.

Because the Workflow Execution might not exist, this API does not take a Run ID as a parameter
Because the Workflow Execution might not exist, this API does not take a Run Id as a parameter
Copy link
Contributor

Choose a reason for hiding this comment

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

Confirmed correct.

@@ -316,12 +316,20 @@ if err != nil {

### Send an Update {#send-update-from-client}

:::tip Stability

In [Pre-release](/evaluate/development-production-features/release-stages#pre-release) (API is subject to change).
Copy link
Contributor

Choose a reason for hiding this comment

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

This needs to be updated to Public Preview. We do not release docs (as a rule) before then, so it should reflect the status when this material is ready for going live.


In [Pre-release](/evaluate/development-production-features/release-stages#pre-release) (API is subject to change).

Minimum recommended [Temporal Server version 1.25](https://github.com/temporalio/temporal/releases/tag/v1.25.0)
Copy link
Contributor

Choose a reason for hiding this comment

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

Consider "Minimum Temporal Server version" unless there's a compelling reason otherwise to be less restrictive.

An Update is a synchronous, blocking call that can change Workflow state, control its flow, and return a result.

A Client sending an Update must wait until the Server delivers the Update to a Worker.
Workers must be available and responsive.
Therefore, provide a context with a timeout to limit the time the client waits for a response.
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
Therefore, provide a context with a timeout to limit the time the client waits for a response.
Setting a timeout with a context provides a hard limit on how long a client will wait for a response.

@@ -332,10 +340,16 @@ You must provide the Workflow Id, but specifying a Run Id is optional.
If you supply only the Workflow Id (and provide an empty string as the Run Id param), the running Workflow Execution receives the Update.

You must provide a `WaitForStage` when calling `UpdateWorkflow()`.
This parameter controls what stage the update must reach before a handle is returned to the caller. If `WaitForStage` is set to `WorkflowUpdateStageCompleted` the handle is returned after the update completes; if `WaitForStage` is set to `WorkflowUpdateStageAccepted` the handle is returned after the Update is accepted (i.e. after the validator has run, if there is a validator).
This parameter controls what stage the update must reach before a handle is returned to the caller.
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
This parameter controls what stage the update must reach before a handle is returned to the caller.
This parameter controls the stage the update must reach before returning a handle to the caller:
- If `WaitForStage` is set to `WorkflowUpdateStageCompleted`, the handle is returned after the Update completes.
- If `WaitForStage` is set to `WorkflowUpdateStageAccepted`, the handle is returned after the Update is accepted and the Validator is run, if it's defined.
Note: You cannot send Updates to other Workflow Executions.
The following sample demonstrates how to create a context with timeout for sending an `Update` to the Workflow:

Or you might consider putting the note into an admonition if important enough.

if err != nil {
log.Fatalf("Unable to get update result: %v", err)
}
```

#### Update-With-Start {#update-with-start}

[Update-with-Start](/encyclopedia/workflow-message-passing#update-with-start) lets you send an Update that checks whether an already-running Workflow with that ID exists.
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggestion:

[Update-with-Start](/encyclopedia/workflow-message-passing#update-with-start) lets you send an Update that checks whether an already-running Workflow with that ID exists:

- If the Workflow exists, the Update is processed.
- If the Workflow does not exist, a new Workflow Execution starts with the given ID, and the Update is processed immediately after.

Upon starting a new Workflow, it immediately processes the Update.

To create a new Update operation, use [`client.NewUpdateWithStartWorkflowOperation`](https://pkg.go.dev/go.temporal.io/sdk/client#NewUpdateWithStartWorkflowOperation).
The Workflow Id is optional - but when it is specified, it must match the one in `StartWorkflowOptions`.
Copy link
Contributor

@fairlydurable fairlydurable Nov 13, 2024

Choose a reason for hiding this comment

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

Suggested change
The Workflow Id is optional - but when it is specified, it must match the one in `StartWorkflowOptions`.
The Workflow Id is optional.
When specified, the Id must match the one used in `StartWorkflowOptions`.


To create a new Update operation, use [`client.NewUpdateWithStartWorkflowOperation`](https://pkg.go.dev/go.temporal.io/sdk/client#NewUpdateWithStartWorkflowOperation).
The Workflow Id is optional - but when it is specified, it must match the one in `StartWorkflowOptions`.
It is invalid to set the Run ID since there might not be running Workflow Execution.
Copy link
Contributor

@fairlydurable fairlydurable Nov 13, 2024

Choose a reason for hiding this comment

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

Suggested change
It is invalid to set the Run ID since there might not be running Workflow Execution.
Since a running Workflow Execution may not already exist, you can't set a Run Id.

The Workflow Id is optional - but when it is specified, it must match the one in `StartWorkflowOptions`.
It is invalid to set the Run ID since there might not be running Workflow Execution.

Use the `WithStartOperation` option to attach an Update Operation to the [`Client.ExecuteWorkflow`](https://pkg.go.dev/go.temporal.io/sdk/client#Client.ExecuteWorkflow) API call.
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
Use the `WithStartOperation` option to attach an Update Operation to the [`Client.ExecuteWorkflow`](https://pkg.go.dev/go.temporal.io/sdk/client#Client.ExecuteWorkflow) API call.
Use the `WithStartOperation` option to attach an Update Operation to the [`Client.ExecuteWorkflow`](https://pkg.go.dev/go.temporal.io/sdk/client#Client.ExecuteWorkflow) API call.
Not all `ExecuteWorkflow` options are allowed with Update-With-Start.
For example, specifying a Cron Schedule will result in an error.
For more details, refer to the [API documentation](https://pkg.go.dev/go.temporal.io/sdk/internal#StartWorkflowOptions).

Refer to the [API documentation](https://pkg.go.dev/go.temporal.io/sdk/internal#StartWorkflowOptions) for further details.

`ExecuteWorkflow` returns once the requested Update wait stage has been reached; or when a provided context times out.
Choose [Workflow Id Conflict Policy](#workflow-id-conflict-policy) "Use Existing" coupled with an indempotent Update handler by default to allow the code to be executed again, in case of client failure.
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
Choose [Workflow Id Conflict Policy](#workflow-id-conflict-policy) "Use Existing" coupled with an indempotent Update handler by default to allow the code to be executed again, in case of client failure.
By default, choose the [Workflow Id Conflict Policy](#workflow-id-conflict-policy) "Use Existing" and use an idempotent Update handler.
This ensures your code can be executed again in case of a Client failure.

`ExecuteWorkflow` returns once the requested Update wait stage has been reached; or when a provided context times out.
Choose [Workflow Id Conflict Policy](#workflow-id-conflict-policy) "Use Existing" coupled with an indempotent Update handler by default to allow the code to be executed again, in case of client failure.

You need a [`WorkflowUpdateHandle`](https://pkg.go.dev/go.temporal.io/sdk/client#WorkflowUpdateHandle) to retrieve a result.
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
You need a [`WorkflowUpdateHandle`](https://pkg.go.dev/go.temporal.io/sdk/client#WorkflowUpdateHandle) to retrieve a result.
Use [`WorkflowUpdateHandle`](https://pkg.go.dev/go.temporal.io/sdk/client#WorkflowUpdateHandle) to retrieve a result from the Update.

Call `Get` on the Update operation.

`UpdateWithStartWorkflowOperation` can only be executed once.
Re-using a previously executed operation returns an error from `ExecuteWorkflow`.
Copy link
Contributor

Choose a reason for hiding this comment

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

Nice.

`UpdateWithStartWorkflowOperation` can only be executed once.
Re-using a previously executed operation returns an error from `ExecuteWorkflow`.

The following example shows the creation, configuration, and use of UpdateWithStart:
Copy link
Contributor

Choose a reason for hiding this comment

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

Also, very nice.


:::

Update-With-Start lets you send an Update that checks whether an already-running Workflow with that ID exists.
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
Update-With-Start lets you send an Update that checks whether an already-running Workflow with that ID exists.
Update-With-Start sends an Update that checks whether an already-running Workflow with that ID exists.

Update-With-Start lets you send an Update that checks whether an already-running Workflow with that ID exists.
If it does, the Update is processed.
If not, it starts a new Workflow Execution with the supplied ID.
Upon starting a new Workflow, it immediately processes the Update.
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
Upon starting a new Workflow, it immediately processes the Update.
When starting a new Workflow, it immediately processes the Update.

If not, it starts a new Workflow Execution with the supplied ID.
Upon starting a new Workflow, it immediately processes the Update.

Update-With-Start is great for latency-sensitive use cases, including the following examples:
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
Update-With-Start is great for latency-sensitive use cases, including the following examples:
Update-With-Start is great for latency-sensitive use cases:

- **Lazy Initialization** -
Instead of making separate Start Workflow and Update Workflow calls, Update-With-Start allows you to send them together in a single roundtrip.
For example, a shopping cart can be modelled using Update-With-Start.
Add or remove an item with an Update.
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
Add or remove an item with an Update.
Updates let you add and remove items from the cart.

Instead of making separate Start Workflow and Update Workflow calls, Update-With-Start allows you to send them together in a single roundtrip.
For example, a shopping cart can be modelled using Update-With-Start.
Add or remove an item with an Update.
Update-With-Start ensures the cart (the Workflow Execution) is created first before applying the Update (state change of items within the cart).
Copy link
Contributor

@fairlydurable fairlydurable Nov 13, 2024

Choose a reason for hiding this comment

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

Suggested change
Update-With-Start ensures the cart (the Workflow Execution) is created first before applying the Update (state change of items within the cart).
Update-With-Start lets the customer start shopping, whether the cart already exists or they've just started shopping.
It ensures the cart, modeled by a Workflow Execution, is created before applying any Update that changes the state of items within the cart.

Update-With-Start ensures the cart (the Workflow Execution) is created first before applying the Update (state change of items within the cart).
- **Early Return** -
Using Update-With-Start can begin a new Workflow Execution and synchronously receiving a response while the Workflow Execution continues to run to completion.
For example, a payment process can be modelled using Update-With-Start.
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
For example, a payment process can be modelled using Update-With-Start.
For example, you might model a payment process using Update-With-Start.

- **Early Return** -
Using Update-With-Start can begin a new Workflow Execution and synchronously receiving a response while the Workflow Execution continues to run to completion.
For example, a payment process can be modelled using Update-With-Start.
You can send the result of payment validation back to the client synchronously, while continuing to complete or rollback the transaction asynchronously.
Copy link
Contributor

@fairlydurable fairlydurable Nov 13, 2024

Choose a reason for hiding this comment

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

Suggested change
You can send the result of payment validation back to the client synchronously, while continuing to complete or rollback the transaction asynchronously.
Whether the payment completes or rolls back, you can send the payment validation results back to the client synchronously, while attempting the transaction asynchronously.

Close?

For example, a payment process can be modelled using Update-With-Start.
You can send the result of payment validation back to the client synchronously, while continuing to complete or rollback the transaction asynchronously.

:::caution
Copy link
Contributor

Choose a reason for hiding this comment

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

I love this admonition.

:::caution

Unlike Signal-with-Start - Update-With-Start is *not* atomic.
If the Update cannot be delivered, for example, when no Worker is running, the Workflow Execution is still started.
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
If the Update cannot be delivered, for example, when no Worker is running, the Workflow Execution is still started.
If the Update can't be delivered, for example, say that there's no running Worker available, a new Workflow Execution will still start.

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