-
Notifications
You must be signed in to change notification settings - Fork 93
Add Standalone Callbacks (rebase) #774
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
base: master
Are you sure you want to change the base?
Changes from all commits
e2ed77e
5757dfe
ad8f707
7c4b67e
8dc0454
2fecc48
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -49,6 +49,28 @@ enum CallbackState { | |
| CALLBACK_STATE_SUCCEEDED = 5; | ||
| // Callback is blocked (eg: by circuit breaker). | ||
| CALLBACK_STATE_BLOCKED = 6; | ||
| // Callback was terminated via TerminateCallbackExecution. Only possible for standalone callbacks. | ||
| CALLBACK_STATE_TERMINATED = 7; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What about timed out? |
||
| // Callback exceeded the schedule-to-close timeout. | ||
| CALLBACK_STATE_TIMED_OUT = 8; | ||
| } | ||
|
|
||
| // Status of a callback execution. | ||
| // The status is only updated twice. First, when the callback is scheduled. And second, when the | ||
| // callback reaches a terminal status. | ||
| // (-- api-linter: core::0216::synonyms=disabled | ||
| // aip.dev/not-precedent: To be consistent with other enums like ActivityExecutionStatus. --) | ||
| enum CallbackExecutionStatus { | ||
| // Default value, unspecified status. | ||
| CALLBACK_EXECUTION_STATUS_UNSPECIFIED = 0; | ||
| // Callback execution is running. | ||
| CALLBACK_EXECUTION_STATUS_RUNNING = 1; | ||
| // Callback has succeeded. | ||
| CALLBACK_EXECUTION_STATUS_SUCCEEDED = 2; | ||
| // Callback has failed. | ||
| CALLBACK_EXECUTION_STATUS_FAILED = 3; | ||
| // Callback was terminated via TerminateCallbackExecution. | ||
| CALLBACK_EXECUTION_STATUS_TERMINATED = 4; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What about timed out?
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If the callback times out, we just use the But I'm assuming you'd like to add it, and I cannot think of a compelling argument not to. 😄 |
||
| } | ||
|
|
||
| // State of a pending Nexus operation. | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -64,6 +64,10 @@ message StartOperationRequest { | |
| map<string, string> callback_header = 6; | ||
| // Links contain caller information and can be attached to the operations started by the handler. | ||
| repeated Link links = 7; | ||
| // Callback token, to uniquely identify the callback as applicable. | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: document the semantics of when to use this field and when to populate the header value. |
||
| // Clients should set both the callback_token and the Temporal-Callback-Token header for | ||
| // compatibility with Workers running older versions of the SDK. | ||
| string callback_token = 8; | ||
| } | ||
|
|
||
| // A request to cancel an operation. | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -22,6 +22,7 @@ import "temporal/api/enums/v1/update.proto"; | |
| import "temporal/api/enums/v1/activity.proto"; | ||
| import "temporal/api/enums/v1/nexus.proto"; | ||
| import "temporal/api/activity/v1/message.proto"; | ||
| import "temporal/api/callback/v1/message.proto"; | ||
| import "temporal/api/common/v1/message.proto"; | ||
| import "temporal/api/history/v1/message.proto"; | ||
| import "temporal/api/workflow/v1/message.proto"; | ||
|
|
@@ -3544,3 +3545,149 @@ message DeleteNexusOperationExecutionRequest { | |
|
|
||
| message DeleteNexusOperationExecutionResponse { | ||
| } | ||
|
|
||
| message StartCallbackExecutionRequest { | ||
| string namespace = 1; | ||
| // The identity of the client who initiated this request. | ||
| string identity = 2; | ||
| // A unique identifier for this start request. Typically UUIDv4. | ||
| string request_id = 3; | ||
| // Identifier for this callback. Required. Must be unique among callbacks in the same namespace. | ||
| // If a callback with this ID already exists, the request will fail with CallbackExecutionAlreadyStarted. | ||
| string callback_id = 4; | ||
| // Information on how this callback should be invoked (e.g. its URL and type). | ||
| temporal.api.common.v1.Callback callback = 5; | ||
| // Schedule-to-close timeout for this callback. | ||
| // (-- api-linter: core::0140::prepositions=disabled | ||
| // aip.dev/not-precedent: "to" is used to indicate interval. --) | ||
| google.protobuf.Duration schedule_to_close_timeout = 6; | ||
| // Search attributes for indexing. | ||
| temporal.api.common.v1.SearchAttributes search_attributes = 7; | ||
| // The input data to deliver to the callback URL. | ||
| oneof input { | ||
| // The Nexus completion data to deliver to the callback URL. | ||
| // Contains either a successful result payload or a failure. | ||
| temporal.api.callback.v1.CallbackExecutionCompletion completion = 8; | ||
| } | ||
| } | ||
|
|
||
| message StartCallbackExecutionResponse { | ||
| // The run ID of the callback that was started. | ||
| string run_id = 1; | ||
| } | ||
|
|
||
| message DescribeCallbackExecutionRequest { | ||
| string namespace = 1; | ||
| // Identifier for the callback. | ||
| string callback_id = 2; | ||
| // Run ID of the callback execution to describe. If empty, the latest run will be described. | ||
| string run_id = 3; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you check what the semantics of a request with an empty run ID with a long poll token? Is that valid in the SAA code?
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That comment is incorrect. Looking at the implementation and doc comments for SAA, it checks that run_id is present if long_poll_token is set. And it's also called out in the doc comment. Will fix. |
||
| // Include the input field in the response. | ||
| bool include_input = 4; | ||
| // Include the outcome (result/failure) in the response if the callback has completed. | ||
| bool include_outcome = 5; | ||
| // Token from a previous DescribeCallbackExecutionResponse. If present, long-poll until the callback | ||
| // state changes from the state encoded in this token. If absent, return current state immediately. | ||
| // If present, run_id must also be present. | ||
| // Note that callback state may change multiple times between requests, therefore it is not | ||
| // guaranteed that a client making a sequence of long-poll requests will see a complete | ||
| // sequence of state changes. | ||
| bytes long_poll_token = 6; | ||
| } | ||
|
|
||
| message DescribeCallbackExecutionResponse { | ||
| // Information about the callback execution. | ||
| temporal.api.callback.v1.CallbackExecutionInfo info = 1; | ||
| // Only set if include_input was true in the request. | ||
| temporal.api.callback.v1.CallbackExecutionCompletion input = 2; | ||
| // Only set if the callback is completed and include_outcome was true in the request. | ||
| temporal.api.callback.v1.CallbackExecutionOutcome outcome = 3; | ||
| // Token for follow-on long-poll requests. Absent only if the callback is complete. | ||
| bytes long_poll_token = 4; | ||
| } | ||
|
|
||
| message PollCallbackExecutionRequest { | ||
| string namespace = 1; | ||
| // Identifier for the callback. | ||
| string callback_id = 2; | ||
| // Run ID of the callback execution to poll. If empty, the latest run will be polled. | ||
| string run_id = 3; | ||
| } | ||
|
|
||
| message PollCallbackExecutionResponse { | ||
| // The run ID of the callback, useful when run_id was not specified in the request. | ||
| string run_id = 1; | ||
| temporal.api.callback.v1.CallbackExecutionOutcome outcome = 2; | ||
| } | ||
|
|
||
| message ListCallbackExecutionsRequest { | ||
| string namespace = 1; | ||
| // Max number of executions to return per page. | ||
| int32 page_size = 2; | ||
| // Token returned in ListCallbackExecutionsResponse. | ||
| bytes next_page_token = 3; | ||
| // Visibility query, see https://docs.temporal.io/list-filter for the syntax. | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please document which search attributes are valid here (and for the count API). |
||
| // Search attributes that are available: | ||
| // - ExecutionStatus | ||
| string query = 4; | ||
| } | ||
|
|
||
| message ListCallbackExecutionsResponse { | ||
| repeated temporal.api.callback.v1.CallbackExecutionListInfo executions = 1; | ||
| // Token to use to fetch the next page. If empty, there is no next page. | ||
| bytes next_page_token = 2; | ||
| } | ||
|
|
||
| message CountCallbackExecutionsRequest { | ||
| string namespace = 1; | ||
| // Visibility query, see https://docs.temporal.io/list-filter for the syntax. | ||
| // Search attributes that are available: | ||
| // - ExecutionStatus | ||
| string query = 2; | ||
| } | ||
|
|
||
| message CountCallbackExecutionsResponse { | ||
| // If `query` is not grouping by any field, the count is an approximate number | ||
| // of callbacks that match the query. | ||
| // If `query` is grouping by a field, the count is simply the sum of the counts | ||
| // of the groups returned in the response. This number can be smaller than the | ||
| // total number of callbacks matching the query. | ||
| int64 count = 1; | ||
|
|
||
| // Contains the groups if the request is grouping by a field. | ||
| // The list might not be complete, and the counts of each group is approximate. | ||
| repeated AggregationGroup groups = 2; | ||
|
|
||
| message AggregationGroup { | ||
| repeated temporal.api.common.v1.Payload group_values = 1; | ||
| int64 count = 2; | ||
| } | ||
| } | ||
|
|
||
| message TerminateCallbackExecutionRequest { | ||
| string namespace = 1; | ||
| // Identifier for the callback. | ||
| string callback_id = 2; | ||
| // Run ID of the callback execution to terminate. If empty, the latest run will be terminated. | ||
| string run_id = 3; | ||
| // The identity of the worker/client. | ||
| string identity = 4; | ||
| // Used to de-dupe termination requests. | ||
| string request_id = 5; | ||
| // Reason for requesting the termination. | ||
| string reason = 6; | ||
| } | ||
|
|
||
| message TerminateCallbackExecutionResponse { | ||
| } | ||
|
|
||
| message DeleteCallbackExecutionRequest { | ||
| string namespace = 1; | ||
| // Identifier for the callback. | ||
| string callback_id = 2; | ||
| // Run ID of the callback execution to delete. If empty, the latest run will be deleted. | ||
| string run_id = 3; | ||
| } | ||
|
|
||
| message DeleteCallbackExecutionResponse { | ||
| } | ||
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.
Maybe put a comment here that implementations should also populate the token header field for compatibility with older servers?