-
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
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 |
|---|---|---|
|
|
@@ -9,12 +9,116 @@ option java_outer_classname = "MessageProto"; | |
| option ruby_package = "Temporalio::Api::Callback::V1"; | ||
| option csharp_namespace = "Temporalio.Api.Callback.V1"; | ||
|
|
||
| import "google/protobuf/duration.proto"; | ||
| import "google/protobuf/empty.proto"; | ||
| import "google/protobuf/timestamp.proto"; | ||
|
|
||
| import "temporal/api/common/v1/message.proto"; | ||
| import "temporal/api/enums/v1/common.proto"; | ||
| import "temporal/api/failure/v1/message.proto"; | ||
|
|
||
| // The outcome of a completed callback execution: either success or a failure. | ||
| message CallbackExecutionOutcome { | ||
| oneof value { | ||
| // The callback completed successfully. (Which includes delivering | ||
| // a Nexus operation that completed with a failure.) | ||
| google.protobuf.Empty success = 1; | ||
| // The failure if the callback completed unsuccessfully. | ||
| temporal.api.failure.v1.Failure failure = 2; | ||
| } | ||
| } | ||
|
|
||
| // The Nexus completion data that a standalone callback execution will deliver to its target URL. | ||
| // Exactly one of success or failure should be set. | ||
| message CallbackExecutionCompletion { | ||
| oneof result { | ||
| // Deliver a successful Nexus operation completion with this result payload. | ||
| // If set, the callback delivers a successful completion to the target URL. | ||
| temporal.api.common.v1.Payload success = 1; | ||
| // Deliver a failed Nexus operation completion with this failure. | ||
| // If set, the callback delivers a failed completion to the target URL. | ||
| // If CanceledFailureInfo is set, the target operation is resolved is canceled instead of failed. | ||
| temporal.api.failure.v1.Failure failure = 2; | ||
| } | ||
| } | ||
|
|
||
| // Information about a standalone callback execution. | ||
| message CallbackExecutionInfo { | ||
| // Unique identifier of this callback within its namespace. | ||
| string callback_id = 1; | ||
|
|
||
| // Run ID of the callback execution. | ||
| string run_id = 2; | ||
|
|
||
| // Information on how this callback should be invoked (e.g. its URL and type). | ||
| temporal.api.common.v1.Callback callback = 3; | ||
|
|
||
| // A general status for this callback, indicates whether it is currently running or in one of the terminal statuses. | ||
| temporal.api.enums.v1.CallbackExecutionStatus status = 4; | ||
|
|
||
| // The detailed state of this callback, provides more granular information than the general status. | ||
| temporal.api.enums.v1.CallbackState state = 5; | ||
|
|
||
| // The number of attempts made to deliver the callback. | ||
| // This number represents a minimum bound since the attempt is incremented after the callback request completes. | ||
| int32 attempt = 6; | ||
|
|
||
| // The time when the callback was created/scheduled. | ||
| google.protobuf.Timestamp create_time = 7; | ||
|
|
||
| // The time when the last attempt completed. | ||
| google.protobuf.Timestamp last_attempt_complete_time = 8; | ||
|
|
||
| // The last attempt's failure, if any. | ||
| temporal.api.failure.v1.Failure last_attempt_failure = 9; | ||
|
|
||
| // The time when the next attempt is scheduled. | ||
| google.protobuf.Timestamp next_attempt_schedule_time = 10; | ||
|
|
||
| // If the state is BLOCKED, provides additional information. | ||
| string blocked_reason = 11; | ||
|
|
||
| // Time when the callback transitioned to a terminal state. | ||
| google.protobuf.Timestamp close_time = 12; | ||
|
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: could you put this next to |
||
|
|
||
| // Search attributes for indexing. | ||
| temporal.api.common.v1.SearchAttributes search_attributes = 13; | ||
|
|
||
| // 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 = 14; | ||
|
|
||
| // Incremented each time the callback's state is mutated in persistence. | ||
| int64 state_transition_count = 15; | ||
| } | ||
|
|
||
| // Limited callback information returned in the list response. | ||
| message CallbackExecutionListInfo { | ||
| // Unique identifier of this callback within its namespace. | ||
| string callback_id = 1; | ||
|
|
||
| // Run ID of the callback execution. | ||
| string run_id = 2; | ||
|
|
||
| // Only running and terminal statuses appear here. More detailed information in CallbackExecutionInfo but not | ||
| // available in the list response. | ||
| temporal.api.enums.v1.CallbackExecutionStatus status = 3; | ||
|
|
||
| // The time when the callback was created/scheduled. | ||
| google.protobuf.Timestamp create_time = 4; | ||
|
|
||
| // Time when the callback transitioned to a terminal state. | ||
| google.protobuf.Timestamp close_time = 5; | ||
|
|
||
| // Search attributes from the start request. | ||
| temporal.api.common.v1.SearchAttributes search_attributes = 6; | ||
|
|
||
| // Incremented each time the callback's state is mutated. | ||
| int64 state_transition_count = 7; | ||
| } | ||
|
|
||
|
|
||
| // Common callback information. Specific CallbackInfo messages should embed this and may include additional fields. | ||
| message CallbackInfo { | ||
| // Information on how this callback should be invoked (e.g. its URL and type). | ||
|
|
@@ -34,4 +138,4 @@ message CallbackInfo { | |
| google.protobuf.Timestamp next_attempt_schedule_time = 7; | ||
| // If the state is BLOCKED, blocked reason provides additional information. | ||
| string blocked_reason = 8; | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -181,6 +181,8 @@ message Callback { | |
| string url = 1; | ||
| // Header to attach to callback request. | ||
| map<string, string> header = 2; | ||
| // Standard token to use for identifying the callback, used for completion. | ||
|
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. Maybe put a comment here that implementations should also populate the token header field for compatibility with older servers? |
||
| string token = 3; | ||
| } | ||
|
|
||
| // Callbacks to be delivered internally within the system. | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -49,6 +49,26 @@ 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? |
||
| } | ||
|
|
||
| // 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? |
||
| } | ||
|
|
||
| // State of a pending Nexus operation. | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -130,6 +130,14 @@ message ActivityExecutionAlreadyStartedFailure { | |
| string run_id = 2; | ||
| } | ||
|
|
||
| // An error indicating that a callback execution failed to start because a callback with the given | ||
| // callback ID already exists in this namespace. | ||
| message CallbackExecutionAlreadyStartedFailure { | ||
| string start_request_id = 1; | ||
| string run_id = 2; | ||
| string callback_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. The other already started failures don't include the business ID, let's not add that here. |
||
| } | ||
|
|
||
| // An error indicating that a Nexus operation failed to start. Returned when there is an existing operation with the | ||
| // given operation ID, and the given ID reuse and conflict policies do not permit starting a new one or attaching to an | ||
| // existing one. | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -64,6 +64,8 @@ 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. |
||
| 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,144 @@ 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 | ||||||
|
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: All other fields have a punctuation. I see this is missing in other messages for the callback_id field too.
Suggested change
|
||||||
| 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? |
||||||
| // 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 callback | ||||||
| // state changes from the state encoded in this token. If absent, return current state immediately. | ||||||
| // 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). |
||||||
| 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. | ||||||
| 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.
We should take a pass at this docstring both here and for Nexus ops. I changed the behavior for Nexus to start from attempt 1 and have a better explanation here:
https://github.com/temporalio/temporal/blob/a05038cf9993ebe043466d3597952e0e29622467/chasm/lib/nexusoperation/proto/v1/operation.proto#L44-L47