Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
937 changes: 917 additions & 20 deletions openapi/openapiv2.json

Large diffs are not rendered by default.

878 changes: 843 additions & 35 deletions openapi/openapiv3.yaml

Large diffs are not rendered by default.

106 changes: 105 additions & 1 deletion temporal/api/callback/v1/message.proto
Original file line number Diff line number Diff line change
Expand Up @@ -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 start callback execution request.
// This number is approximate. There could be more attempts if the server crashes before recording the attempt's completion, or fewer
// if the callback was terminated or timed out after the counter has been incremented and before an attempt could be made.
int32 attempt = 6;

// The time when the callback was created/scheduled.
google.protobuf.Timestamp create_time = 7;
// Time when the callback transitioned to a terminal state.
google.protobuf.Timestamp close_time = 12;

// 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 (only set when in BACKING_OFF state).
google.protobuf.Timestamp next_attempt_schedule_time = 10;

// If the state is BLOCKED, provides additional information.
string blocked_reason = 11;

// 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).
Expand All @@ -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;
}
}
3 changes: 3 additions & 0 deletions temporal/api/common/v1/message.proto
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,9 @@ 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.
Copy link
Copy Markdown
Member

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?

// Clients should also populate the token header field for compatibility with older servers.
string token = 3;
}

// Callbacks to be delivered internally within the system.
Expand Down
22 changes: 22 additions & 0 deletions temporal/api/enums/v1/common.proto
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The 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;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

What about timed out?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

If the callback times out, we just use the STATUS_FAILED state, and set the TimeoutFailureInfo field in the terminal failure proto.

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.
Expand Down
12 changes: 12 additions & 0 deletions temporal/api/errordetails/v1/message.proto
Original file line number Diff line number Diff line change
Expand Up @@ -130,10 +130,22 @@ message ActivityExecutionAlreadyStartedFailure {
string run_id = 2;
}

// An error indicating that a callback execution failed to start because a callback with the same
// callback ID already exists in this namespace.
message CallbackExecutionAlreadyStartedFailure {
string start_request_id = 1;
string run_id = 2;
}

// 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.
message NexusOperationExecutionAlreadyStartedFailure {
string start_request_id = 1;
string run_id = 2;
}

// An error indicating that the request's targeted Nexus operation has not yet started.
message NexusOperationNotStartedFailure {
string start_request_id = 1;
}
4 changes: 4 additions & 0 deletions temporal/api/nexus/v1/message.proto
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The 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.
Expand Down
147 changes: 147 additions & 0 deletions temporal/api/workflowservice/v1/request_response.proto
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -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;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The 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?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The 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.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The 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 {
}
Loading
Loading