From 9109f60c3687976d267128f98adfb798fd24e97c Mon Sep 17 00:00:00 2001 From: Mohammad Dashti Date: Mon, 14 Sep 2026 15:58:31 -0700 Subject: [PATCH 1/9] Added the stream messages, commands, events, and task carriage. --- temporal/api/command/v1/message.proto | 27 ++++++++++ temporal/api/enums/v1/command_type.proto | 2 + temporal/api/enums/v1/event_type.proto | 8 +++ temporal/api/history/v1/message.proto | 36 +++++++++++++ temporal/api/stream/v1/message.proto | 51 +++++++++++++++++++ .../workflowservice/v1/request_response.proto | 5 ++ 6 files changed, 129 insertions(+) create mode 100644 temporal/api/stream/v1/message.proto diff --git a/temporal/api/command/v1/message.proto b/temporal/api/command/v1/message.proto index ee839115b..311b918e4 100644 --- a/temporal/api/command/v1/message.proto +++ b/temporal/api/command/v1/message.proto @@ -14,6 +14,7 @@ import "google/protobuf/duration.proto"; import "temporal/api/enums/v1/workflow.proto"; import "temporal/api/enums/v1/command_type.proto"; import "temporal/api/common/v1/message.proto"; +import "temporal/api/stream/v1/message.proto"; import "temporal/api/failure/v1/message.proto"; import "temporal/api/taskqueue/v1/message.proto"; import "temporal/api/workflow/v1/message.proto"; @@ -324,5 +325,31 @@ message Command { ScheduleNexusOperationCommandAttributes schedule_nexus_operation_command_attributes = 18; RequestCancelNexusOperationCommandAttributes request_cancel_nexus_operation_command_attributes = 19; + AddStreamMessagesCommandAttributes add_stream_messages_command_attributes = 20; + SubscribeStreamCommandAttributes subscribe_stream_command_attributes = 21; } } + +// Appends to a stream the Workflow owns. Applied inside the Workflow Task's own +// commit, so it emits no History Event and does not schedule further work. +message AddStreamMessagesCommandAttributes { + // Empty means the Workflow's default output stream. + string stream_id = 1; + repeated temporal.api.stream.v1.StreamMessage messages = 2; +} + +// Subscribe this Workflow to a stream, so later Workflow Tasks carry the ranges +// it has not consumed yet. +// +// The stream's addressing is resolved by the server rather than supplied here. +// A Workflow cannot look it up without doing I/O, and a value it carried would +// be a reading rather than a fact, so it could differ on replay. +message SubscribeStreamCommandAttributes { + // Stream to consume. A stream in another execution is addressed by its id; + // one this Workflow owns is addressed by the name it was published under. + string stream_id = 1; + // Where to start. Negative means from wherever the stream is when the + // subscription is registered, which the server resolves and records so + // replay does not resolve it again. + int64 start_offset = 2; +} diff --git a/temporal/api/enums/v1/command_type.proto b/temporal/api/enums/v1/command_type.proto index 067d95391..677ed3b2d 100644 --- a/temporal/api/enums/v1/command_type.proto +++ b/temporal/api/enums/v1/command_type.proto @@ -29,4 +29,6 @@ enum CommandType { COMMAND_TYPE_MODIFY_WORKFLOW_PROPERTIES = 16; COMMAND_TYPE_SCHEDULE_NEXUS_OPERATION = 17; COMMAND_TYPE_REQUEST_CANCEL_NEXUS_OPERATION = 18; + COMMAND_TYPE_ADD_STREAM_MESSAGES = 19; + COMMAND_TYPE_SUBSCRIBE_STREAM = 20; } diff --git a/temporal/api/enums/v1/event_type.proto b/temporal/api/enums/v1/event_type.proto index b879f51e8..b515acb1d 100644 --- a/temporal/api/enums/v1/event_type.proto +++ b/temporal/api/enums/v1/event_type.proto @@ -175,4 +175,12 @@ enum EventType { EVENT_TYPE_WORKFLOW_EXECUTION_UNPAUSED = 59; // An event that indicates time skipping advanced time or was disabled automatically after a bound was reached. EVENT_TYPE_WORKFLOW_EXECUTION_TIME_SKIPPING_TRANSITIONED = 60; + // A Workflow subscribed to a stream. Recorded once per subscription, not + // per message: the offsets a task consumed ride WorkflowTaskCompleted and + // the payloads never enter History at all. + EVENT_TYPE_WORKFLOW_STREAM_SUBSCRIBED = 61; + // A Workflow published a batch of messages to a stream. Recorded per + // batch, and carrying only the offset range it landed at: the bodies go to + // the stream's own log, never into History. + EVENT_TYPE_WORKFLOW_STREAM_MESSAGES_ADDED = 62; } diff --git a/temporal/api/history/v1/message.proto b/temporal/api/history/v1/message.proto index b40324d68..089dccf78 100644 --- a/temporal/api/history/v1/message.proto +++ b/temporal/api/history/v1/message.proto @@ -17,6 +17,7 @@ import "temporal/api/enums/v1/failed_cause.proto"; import "temporal/api/enums/v1/update.proto"; import "temporal/api/enums/v1/workflow.proto"; import "temporal/api/common/v1/message.proto"; +import "temporal/api/stream/v1/message.proto"; import "temporal/api/deployment/v1/message.proto"; import "temporal/api/failure/v1/message.proto"; import "temporal/api/taskqueue/v1/message.proto"; @@ -369,6 +370,12 @@ message WorkflowTaskCompletedEventAttributes { // execution. UNSPECIFIED means the task was completed by an unversioned worker. This value // updates workflow execution's `versioning_info.behavior`. temporal.api.enums.v1.VersioningBehavior versioning_behavior = 8; + + // Offset ranges this Workflow Task consumed from streams it subscribes to. + // Recorded on every task where a subscription is active, including when it + // observed nothing: an empty range is a fact replay must reproduce, and + // omitting it would let replay deliver messages the Workflow did not have. + repeated temporal.api.stream.v1.StreamCursor stream_cursors = 20; // The Worker Deployment Version that completed this task. Must be set if `versioning_behavior` // is set. This value updates workflow execution's `versioning_info.version`. // Deprecated. Replaced with `deployment_version`. @@ -955,6 +962,33 @@ message ActivityPropertiesModifiedExternallyEventAttributes { temporal.api.common.v1.RetryPolicy new_retry_policy = 2; } +message WorkflowStreamSubscribedEventAttributes { + // The WorkflowTaskCompleted event of the task whose command created this + // subscription. + int64 workflow_task_completed_event_id = 1; + // Stream the Workflow subscribed to. + string stream_id = 2; + // The offset the subscription actually starts from. Resolved by the server + // when the subscription is registered and recorded here, so replay reads + // the resolved value rather than resolving it again against a stream that + // has since moved. + int64 start_offset = 3; +} + +message WorkflowStreamMessagesAddedEventAttributes { + // The WorkflowTaskCompleted event of the task whose command published this + // batch. + int64 workflow_task_completed_event_id = 1; + // Stream the Workflow published to. + string stream_id = 2; + // Offset the first message of the batch landed at. + int64 first_offset = 3; + // How many messages the batch held. With first_offset this names the range + // without carrying any of it, which is what keeps this event a fixed size + // no matter how large the batch or its payloads are. + int64 message_count = 4; +} + message WorkflowExecutionUpdateAcceptedEventAttributes { // The instance ID of the update protocol that generated this event. string protocol_instance_id = 1; @@ -1278,6 +1312,8 @@ message HistoryEvent { WorkflowExecutionPausedEventAttributes workflow_execution_paused_event_attributes = 63; WorkflowExecutionUnpausedEventAttributes workflow_execution_unpaused_event_attributes = 64; WorkflowExecutionTimeSkippingTransitionedEventAttributes workflow_execution_time_skipping_transitioned_event_attributes = 65; + WorkflowStreamSubscribedEventAttributes workflow_stream_subscribed_event_attributes = 66; + WorkflowStreamMessagesAddedEventAttributes workflow_stream_messages_added_event_attributes = 67; } } diff --git a/temporal/api/stream/v1/message.proto b/temporal/api/stream/v1/message.proto new file mode 100644 index 000000000..a1702e3c7 --- /dev/null +++ b/temporal/api/stream/v1/message.proto @@ -0,0 +1,51 @@ +syntax = "proto3"; + +package temporal.api.stream.v1; + +option go_package = "go.temporal.io/api/stream/v1;stream"; +option java_package = "io.temporal.api.stream.v1"; +option java_multiple_files = true; +option java_outer_classname = "MessageProto"; +option ruby_package = "Temporalio::Api::Stream::V1"; +option csharp_namespace = "Temporalio.Api.Stream.V1"; + +import "temporal/api/common/v1/message.proto"; + +message StreamMessage { + temporal.api.common.v1.Payload body = 1; + map metadata = 2; + string topic = 3; + int64 topic_sequence = 4; +} + +// A contiguous range of a stream delivered to a Workflow Task, along with the +// offsets it covers. The offsets are what History records; the messages +// themselves are never written to History. +message StreamSlice { + string stream_id = 1; + string run_id = 2; + // Inclusive. + int64 from_offset = 3; + // Exclusive. Equal to from_offset when the subscription observed nothing, + // which is a fact replay has to reproduce rather than an absence of one. + int64 to_offset = 4; + repeated StreamMessage messages = 5; + // The WorkflowTaskCompleted event whose stream_cursors recorded this range. + // Set only when the server is re-supplying a range for a task being + // replayed; a slice for the task now being started leaves it unset, because + // the event closing that task does not exist yet. + // + // Replay needs this because a Workflow Task response carries one slice set + // while a cache miss replays every prior task, so the ranges have to be + // matched to the events that recorded them rather than to the response. + int64 workflow_task_completed_event_id = 6; +} + +// The offsets a Workflow Task consumed, without the payloads. Recorded on +// WorkflowTaskCompleted so History grows with Workflow Tasks rather than with +// messages. +message StreamCursor { + string stream_id = 1; + int64 from_offset = 2; + int64 to_offset = 3; +} diff --git a/temporal/api/workflowservice/v1/request_response.proto b/temporal/api/workflowservice/v1/request_response.proto index 1aae988d8..93cd0e8b4 100644 --- a/temporal/api/workflowservice/v1/request_response.proto +++ b/temporal/api/workflowservice/v1/request_response.proto @@ -24,6 +24,7 @@ import "temporal/api/enums/v1/activity.proto"; import "temporal/api/enums/v1/nexus.proto"; import "temporal/api/activity/v1/message.proto"; import "temporal/api/common/v1/message.proto"; +import "temporal/api/stream/v1/message.proto"; import "temporal/api/history/v1/message.proto"; import "temporal/api/workflow/v1/message.proto"; import "temporal/api/command/v1/message.proto"; @@ -384,6 +385,10 @@ message PollWorkflowTaskQueueResponse { // 3. If every group has some pending polls, assign the next poll to a group randomly // according to the weights. temporal.api.taskqueue.v1.PollerGroupsInfo poller_groups_info = 19; + + // Stream data attached to this task. Delivered out of band so the payloads + // never enter History; only the offset ranges are recorded there. + repeated temporal.api.stream.v1.StreamSlice stream_slices = 20; } message RespondWorkflowTaskCompletedRequest { From 7caf5c39a841ada0a3e82d86539dcab9116ad32b Mon Sep 17 00:00:00 2001 From: Mohammad Dashti Date: Wed, 16 Sep 2026 14:48:13 -0700 Subject: [PATCH 2/9] Exempted the stream proto from the prepositions rule. A half-open range reads as `from_offset`/`to_offset` in the server's own protos, and AIP-140 rejects both names. --- api-linter.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/api-linter.yaml b/api-linter.yaml index 290842854..5a38d2b4c 100644 --- a/api-linter.yaml +++ b/api-linter.yaml @@ -12,6 +12,11 @@ disabled_rules: - "core::0123::resource-annotation" # We don't require resource annotations on all messages -- https://linter.aip.dev/123/resource-annotation +- included_paths: + - "**/stream/v1/message.proto" + disabled_rules: + - "core::0140::prepositions" # Half-open offset ranges are spelled `from_offset`/`to_offset` here and in the server's own protos -- https://linter.aip.dev/140/prepositions + - included_paths: - "**/workflowservice/v1/request_response.proto" - "**/operatorservice/v1/request_response.proto" From 2b05496592da2a818e137895ec417203c6b36d5f Mon Sep 17 00:00:00 2001 From: Mohammad Dashti Date: Wed, 16 Sep 2026 14:48:13 -0700 Subject: [PATCH 3/9] Regenerated the OpenAPI specs. `make http-api-docs` picks up the stream slices on the poll response and the two new event types, so the committed specs were stale. --- openapi/openapiv2.json | 143 ++++++++++++++++++++++++++++++++++++++++- openapi/openapiv3.yaml | 126 ++++++++++++++++++++++++++++++++++++ 2 files changed, 267 insertions(+), 2 deletions(-) diff --git a/openapi/openapiv2.json b/openapi/openapiv2.json index 0b643ceb7..541226bd6 100644 --- a/openapi/openapiv2.json +++ b/openapi/openapiv2.json @@ -16116,10 +16116,12 @@ "EVENT_TYPE_NEXUS_OPERATION_CANCEL_REQUEST_FAILED", "EVENT_TYPE_WORKFLOW_EXECUTION_PAUSED", "EVENT_TYPE_WORKFLOW_EXECUTION_UNPAUSED", - "EVENT_TYPE_WORKFLOW_EXECUTION_TIME_SKIPPING_TRANSITIONED" + "EVENT_TYPE_WORKFLOW_EXECUTION_TIME_SKIPPING_TRANSITIONED", + "EVENT_TYPE_WORKFLOW_STREAM_SUBSCRIBED", + "EVENT_TYPE_WORKFLOW_STREAM_MESSAGES_ADDED" ], "default": "EVENT_TYPE_UNSPECIFIED", - "description": "- EVENT_TYPE_UNSPECIFIED: Place holder and should never appear in a Workflow execution history\n - EVENT_TYPE_WORKFLOW_EXECUTION_STARTED: Workflow execution has been triggered/started\nIt contains Workflow execution inputs, as well as Workflow timeout configurations\n - EVENT_TYPE_WORKFLOW_EXECUTION_COMPLETED: Workflow execution has successfully completed and contains Workflow execution results\n - EVENT_TYPE_WORKFLOW_EXECUTION_FAILED: Workflow execution has unsuccessfully completed and contains the Workflow execution error\n - EVENT_TYPE_WORKFLOW_EXECUTION_TIMED_OUT: Workflow execution has timed out by the Temporal Server\nUsually due to the Workflow having not been completed within timeout settings\n - EVENT_TYPE_WORKFLOW_TASK_SCHEDULED: Workflow Task has been scheduled and the SDK client should now be able to process any new history events\n - EVENT_TYPE_WORKFLOW_TASK_STARTED: Workflow Task has started and the SDK client has picked up the Workflow Task and is processing new history events\n - EVENT_TYPE_WORKFLOW_TASK_COMPLETED: Workflow Task has completed\nThe SDK client picked up the Workflow Task and processed new history events\nSDK client may or may not ask the Temporal Server to do additional work, such as:\nEVENT_TYPE_ACTIVITY_TASK_SCHEDULED\nEVENT_TYPE_TIMER_STARTED\nEVENT_TYPE_UPSERT_WORKFLOW_SEARCH_ATTRIBUTES\nEVENT_TYPE_MARKER_RECORDED\nEVENT_TYPE_START_CHILD_WORKFLOW_EXECUTION_INITIATED\nEVENT_TYPE_REQUEST_CANCEL_EXTERNAL_WORKFLOW_EXECUTION_INITIATED\nEVENT_TYPE_SIGNAL_EXTERNAL_WORKFLOW_EXECUTION_INITIATED\nEVENT_TYPE_WORKFLOW_EXECUTION_COMPLETED\nEVENT_TYPE_WORKFLOW_EXECUTION_FAILED\nEVENT_TYPE_WORKFLOW_EXECUTION_CANCELED\nEVENT_TYPE_WORKFLOW_EXECUTION_CONTINUED_AS_NEW\n - EVENT_TYPE_WORKFLOW_TASK_TIMED_OUT: Workflow Task encountered a timeout\nEither an SDK client with a local cache was not available at the time, or it took too long for the SDK client to process the task\n - EVENT_TYPE_WORKFLOW_TASK_FAILED: Workflow Task encountered a failure\nUsually this means that the Workflow was non-deterministic\nHowever, the Workflow reset functionality also uses this event\n - EVENT_TYPE_ACTIVITY_TASK_SCHEDULED: Activity Task was scheduled\nThe SDK client should pick up this activity task and execute\nThis event type contains activity inputs, as well as activity timeout configurations\n - EVENT_TYPE_ACTIVITY_TASK_STARTED: Activity Task has started executing\nThe SDK client has picked up the Activity Task and is processing the Activity invocation\n - EVENT_TYPE_ACTIVITY_TASK_COMPLETED: Activity Task has finished successfully\nThe SDK client has picked up and successfully completed the Activity Task\nThis event type contains Activity execution results\n - EVENT_TYPE_ACTIVITY_TASK_FAILED: Activity Task has finished unsuccessfully\nThe SDK picked up the Activity Task but unsuccessfully completed it\nThis event type contains Activity execution errors\n - EVENT_TYPE_ACTIVITY_TASK_TIMED_OUT: Activity has timed out according to the Temporal Server\nActivity did not complete within the timeout settings\n - EVENT_TYPE_ACTIVITY_TASK_CANCEL_REQUESTED: A request to cancel the Activity has occurred\nThe SDK client will be able to confirm cancellation of an Activity during an Activity heartbeat\n - EVENT_TYPE_ACTIVITY_TASK_CANCELED: Activity has been cancelled\n - EVENT_TYPE_TIMER_STARTED: A timer has started\n - EVENT_TYPE_TIMER_FIRED: A timer has fired\n - EVENT_TYPE_TIMER_CANCELED: A time has been cancelled\n - EVENT_TYPE_WORKFLOW_EXECUTION_CANCEL_REQUESTED: A request has been made to cancel the Workflow execution\n - EVENT_TYPE_WORKFLOW_EXECUTION_CANCELED: SDK client has confirmed the cancellation request and the Workflow execution has been cancelled\n - EVENT_TYPE_REQUEST_CANCEL_EXTERNAL_WORKFLOW_EXECUTION_INITIATED: Workflow has requested that the Temporal Server try to cancel another Workflow\n - EVENT_TYPE_REQUEST_CANCEL_EXTERNAL_WORKFLOW_EXECUTION_FAILED: Temporal Server could not cancel the targeted Workflow\nThis is usually because the target Workflow could not be found\n - EVENT_TYPE_EXTERNAL_WORKFLOW_EXECUTION_CANCEL_REQUESTED: Temporal Server has successfully requested the cancellation of the target Workflow\n - EVENT_TYPE_MARKER_RECORDED: A marker has been recorded.\nThis event type is transparent to the Temporal Server\nThe Server will only store it and will not try to understand it.\n - EVENT_TYPE_WORKFLOW_EXECUTION_SIGNALED: Workflow has received a Signal event\nThe event type contains the Signal name, as well as a Signal payload\n - EVENT_TYPE_WORKFLOW_EXECUTION_TERMINATED: Workflow execution has been forcefully terminated\nThis is usually because the terminate Workflow API was called\n - EVENT_TYPE_WORKFLOW_EXECUTION_CONTINUED_AS_NEW: Workflow has successfully completed and a new Workflow has been started within the same transaction\nContains last Workflow execution results as well as new Workflow execution inputs\n - EVENT_TYPE_START_CHILD_WORKFLOW_EXECUTION_INITIATED: Temporal Server will try to start a child Workflow\n - EVENT_TYPE_START_CHILD_WORKFLOW_EXECUTION_FAILED: Child Workflow execution cannot be started/triggered\nUsually due to a child Workflow ID collision\n - EVENT_TYPE_CHILD_WORKFLOW_EXECUTION_STARTED: Child Workflow execution has successfully started/triggered\n - EVENT_TYPE_CHILD_WORKFLOW_EXECUTION_COMPLETED: Child Workflow execution has successfully completed\n - EVENT_TYPE_CHILD_WORKFLOW_EXECUTION_FAILED: Child Workflow execution has unsuccessfully completed\n - EVENT_TYPE_CHILD_WORKFLOW_EXECUTION_CANCELED: Child Workflow execution has been cancelled\n - EVENT_TYPE_CHILD_WORKFLOW_EXECUTION_TIMED_OUT: Child Workflow execution has timed out by the Temporal Server\n - EVENT_TYPE_CHILD_WORKFLOW_EXECUTION_TERMINATED: Child Workflow execution has been terminated\n - EVENT_TYPE_SIGNAL_EXTERNAL_WORKFLOW_EXECUTION_INITIATED: Temporal Server will try to Signal the targeted Workflow\nContains the Signal name, as well as a Signal payload\n - EVENT_TYPE_SIGNAL_EXTERNAL_WORKFLOW_EXECUTION_FAILED: Temporal Server cannot Signal the targeted Workflow\nUsually because the Workflow could not be found\n - EVENT_TYPE_EXTERNAL_WORKFLOW_EXECUTION_SIGNALED: Temporal Server has successfully Signaled the targeted Workflow\n - EVENT_TYPE_UPSERT_WORKFLOW_SEARCH_ATTRIBUTES: Workflow search attributes should be updated and synchronized with the visibility store\n - EVENT_TYPE_WORKFLOW_EXECUTION_UPDATE_ADMITTED: An update was admitted. Note that not all admitted updates result in this\nevent. See UpdateAdmittedEventOrigin for situations in which this event\nis created.\n - EVENT_TYPE_WORKFLOW_EXECUTION_UPDATE_ACCEPTED: An update was accepted (i.e. passed validation, perhaps because no validator was defined)\n - EVENT_TYPE_WORKFLOW_EXECUTION_UPDATE_REJECTED: This event is never written to history.\n - EVENT_TYPE_WORKFLOW_EXECUTION_UPDATE_COMPLETED: An update completed\n - EVENT_TYPE_WORKFLOW_PROPERTIES_MODIFIED_EXTERNALLY: Some property or properties of the workflow as a whole have changed by non-workflow code.\nThe distinction of external vs. command-based modification is important so the SDK can\nmaintain determinism when using the command-based approach.\n - EVENT_TYPE_ACTIVITY_PROPERTIES_MODIFIED_EXTERNALLY: Some property or properties of an already-scheduled activity have changed by non-workflow code.\nThe distinction of external vs. command-based modification is important so the SDK can\nmaintain determinism when using the command-based approach.\n - EVENT_TYPE_WORKFLOW_PROPERTIES_MODIFIED: Workflow properties modified by user workflow code\n - EVENT_TYPE_NEXUS_OPERATION_SCHEDULED: A Nexus operation was scheduled using a ScheduleNexusOperation command.\n - EVENT_TYPE_NEXUS_OPERATION_STARTED: An asynchronous Nexus operation was started by a Nexus handler.\n - EVENT_TYPE_NEXUS_OPERATION_COMPLETED: A Nexus operation completed successfully.\n - EVENT_TYPE_NEXUS_OPERATION_FAILED: A Nexus operation failed.\n - EVENT_TYPE_NEXUS_OPERATION_CANCELED: A Nexus operation completed as canceled.\n - EVENT_TYPE_NEXUS_OPERATION_TIMED_OUT: A Nexus operation timed out.\n - EVENT_TYPE_NEXUS_OPERATION_CANCEL_REQUESTED: A Nexus operation was requested to be canceled using a RequestCancelNexusOperation command.\n - EVENT_TYPE_WORKFLOW_EXECUTION_OPTIONS_UPDATED: Workflow execution options updated by user.\n - EVENT_TYPE_NEXUS_OPERATION_CANCEL_REQUEST_COMPLETED: A cancellation request for a Nexus operation was successfully delivered to the Nexus handler.\n - EVENT_TYPE_NEXUS_OPERATION_CANCEL_REQUEST_FAILED: A cancellation request for a Nexus operation resulted in an error.\n - EVENT_TYPE_WORKFLOW_EXECUTION_PAUSED: An event that indicates that the workflow execution has been paused.\n - EVENT_TYPE_WORKFLOW_EXECUTION_UNPAUSED: An event that indicates that the previously paused workflow execution has been unpaused.\n - EVENT_TYPE_WORKFLOW_EXECUTION_TIME_SKIPPING_TRANSITIONED: An event that indicates time skipping advanced time or was disabled automatically after a bound was reached.", + "description": "- EVENT_TYPE_UNSPECIFIED: Place holder and should never appear in a Workflow execution history\n - EVENT_TYPE_WORKFLOW_EXECUTION_STARTED: Workflow execution has been triggered/started\nIt contains Workflow execution inputs, as well as Workflow timeout configurations\n - EVENT_TYPE_WORKFLOW_EXECUTION_COMPLETED: Workflow execution has successfully completed and contains Workflow execution results\n - EVENT_TYPE_WORKFLOW_EXECUTION_FAILED: Workflow execution has unsuccessfully completed and contains the Workflow execution error\n - EVENT_TYPE_WORKFLOW_EXECUTION_TIMED_OUT: Workflow execution has timed out by the Temporal Server\nUsually due to the Workflow having not been completed within timeout settings\n - EVENT_TYPE_WORKFLOW_TASK_SCHEDULED: Workflow Task has been scheduled and the SDK client should now be able to process any new history events\n - EVENT_TYPE_WORKFLOW_TASK_STARTED: Workflow Task has started and the SDK client has picked up the Workflow Task and is processing new history events\n - EVENT_TYPE_WORKFLOW_TASK_COMPLETED: Workflow Task has completed\nThe SDK client picked up the Workflow Task and processed new history events\nSDK client may or may not ask the Temporal Server to do additional work, such as:\nEVENT_TYPE_ACTIVITY_TASK_SCHEDULED\nEVENT_TYPE_TIMER_STARTED\nEVENT_TYPE_UPSERT_WORKFLOW_SEARCH_ATTRIBUTES\nEVENT_TYPE_MARKER_RECORDED\nEVENT_TYPE_START_CHILD_WORKFLOW_EXECUTION_INITIATED\nEVENT_TYPE_REQUEST_CANCEL_EXTERNAL_WORKFLOW_EXECUTION_INITIATED\nEVENT_TYPE_SIGNAL_EXTERNAL_WORKFLOW_EXECUTION_INITIATED\nEVENT_TYPE_WORKFLOW_EXECUTION_COMPLETED\nEVENT_TYPE_WORKFLOW_EXECUTION_FAILED\nEVENT_TYPE_WORKFLOW_EXECUTION_CANCELED\nEVENT_TYPE_WORKFLOW_EXECUTION_CONTINUED_AS_NEW\n - EVENT_TYPE_WORKFLOW_TASK_TIMED_OUT: Workflow Task encountered a timeout\nEither an SDK client with a local cache was not available at the time, or it took too long for the SDK client to process the task\n - EVENT_TYPE_WORKFLOW_TASK_FAILED: Workflow Task encountered a failure\nUsually this means that the Workflow was non-deterministic\nHowever, the Workflow reset functionality also uses this event\n - EVENT_TYPE_ACTIVITY_TASK_SCHEDULED: Activity Task was scheduled\nThe SDK client should pick up this activity task and execute\nThis event type contains activity inputs, as well as activity timeout configurations\n - EVENT_TYPE_ACTIVITY_TASK_STARTED: Activity Task has started executing\nThe SDK client has picked up the Activity Task and is processing the Activity invocation\n - EVENT_TYPE_ACTIVITY_TASK_COMPLETED: Activity Task has finished successfully\nThe SDK client has picked up and successfully completed the Activity Task\nThis event type contains Activity execution results\n - EVENT_TYPE_ACTIVITY_TASK_FAILED: Activity Task has finished unsuccessfully\nThe SDK picked up the Activity Task but unsuccessfully completed it\nThis event type contains Activity execution errors\n - EVENT_TYPE_ACTIVITY_TASK_TIMED_OUT: Activity has timed out according to the Temporal Server\nActivity did not complete within the timeout settings\n - EVENT_TYPE_ACTIVITY_TASK_CANCEL_REQUESTED: A request to cancel the Activity has occurred\nThe SDK client will be able to confirm cancellation of an Activity during an Activity heartbeat\n - EVENT_TYPE_ACTIVITY_TASK_CANCELED: Activity has been cancelled\n - EVENT_TYPE_TIMER_STARTED: A timer has started\n - EVENT_TYPE_TIMER_FIRED: A timer has fired\n - EVENT_TYPE_TIMER_CANCELED: A time has been cancelled\n - EVENT_TYPE_WORKFLOW_EXECUTION_CANCEL_REQUESTED: A request has been made to cancel the Workflow execution\n - EVENT_TYPE_WORKFLOW_EXECUTION_CANCELED: SDK client has confirmed the cancellation request and the Workflow execution has been cancelled\n - EVENT_TYPE_REQUEST_CANCEL_EXTERNAL_WORKFLOW_EXECUTION_INITIATED: Workflow has requested that the Temporal Server try to cancel another Workflow\n - EVENT_TYPE_REQUEST_CANCEL_EXTERNAL_WORKFLOW_EXECUTION_FAILED: Temporal Server could not cancel the targeted Workflow\nThis is usually because the target Workflow could not be found\n - EVENT_TYPE_EXTERNAL_WORKFLOW_EXECUTION_CANCEL_REQUESTED: Temporal Server has successfully requested the cancellation of the target Workflow\n - EVENT_TYPE_MARKER_RECORDED: A marker has been recorded.\nThis event type is transparent to the Temporal Server\nThe Server will only store it and will not try to understand it.\n - EVENT_TYPE_WORKFLOW_EXECUTION_SIGNALED: Workflow has received a Signal event\nThe event type contains the Signal name, as well as a Signal payload\n - EVENT_TYPE_WORKFLOW_EXECUTION_TERMINATED: Workflow execution has been forcefully terminated\nThis is usually because the terminate Workflow API was called\n - EVENT_TYPE_WORKFLOW_EXECUTION_CONTINUED_AS_NEW: Workflow has successfully completed and a new Workflow has been started within the same transaction\nContains last Workflow execution results as well as new Workflow execution inputs\n - EVENT_TYPE_START_CHILD_WORKFLOW_EXECUTION_INITIATED: Temporal Server will try to start a child Workflow\n - EVENT_TYPE_START_CHILD_WORKFLOW_EXECUTION_FAILED: Child Workflow execution cannot be started/triggered\nUsually due to a child Workflow ID collision\n - EVENT_TYPE_CHILD_WORKFLOW_EXECUTION_STARTED: Child Workflow execution has successfully started/triggered\n - EVENT_TYPE_CHILD_WORKFLOW_EXECUTION_COMPLETED: Child Workflow execution has successfully completed\n - EVENT_TYPE_CHILD_WORKFLOW_EXECUTION_FAILED: Child Workflow execution has unsuccessfully completed\n - EVENT_TYPE_CHILD_WORKFLOW_EXECUTION_CANCELED: Child Workflow execution has been cancelled\n - EVENT_TYPE_CHILD_WORKFLOW_EXECUTION_TIMED_OUT: Child Workflow execution has timed out by the Temporal Server\n - EVENT_TYPE_CHILD_WORKFLOW_EXECUTION_TERMINATED: Child Workflow execution has been terminated\n - EVENT_TYPE_SIGNAL_EXTERNAL_WORKFLOW_EXECUTION_INITIATED: Temporal Server will try to Signal the targeted Workflow\nContains the Signal name, as well as a Signal payload\n - EVENT_TYPE_SIGNAL_EXTERNAL_WORKFLOW_EXECUTION_FAILED: Temporal Server cannot Signal the targeted Workflow\nUsually because the Workflow could not be found\n - EVENT_TYPE_EXTERNAL_WORKFLOW_EXECUTION_SIGNALED: Temporal Server has successfully Signaled the targeted Workflow\n - EVENT_TYPE_UPSERT_WORKFLOW_SEARCH_ATTRIBUTES: Workflow search attributes should be updated and synchronized with the visibility store\n - EVENT_TYPE_WORKFLOW_EXECUTION_UPDATE_ADMITTED: An update was admitted. Note that not all admitted updates result in this\nevent. See UpdateAdmittedEventOrigin for situations in which this event\nis created.\n - EVENT_TYPE_WORKFLOW_EXECUTION_UPDATE_ACCEPTED: An update was accepted (i.e. passed validation, perhaps because no validator was defined)\n - EVENT_TYPE_WORKFLOW_EXECUTION_UPDATE_REJECTED: This event is never written to history.\n - EVENT_TYPE_WORKFLOW_EXECUTION_UPDATE_COMPLETED: An update completed\n - EVENT_TYPE_WORKFLOW_PROPERTIES_MODIFIED_EXTERNALLY: Some property or properties of the workflow as a whole have changed by non-workflow code.\nThe distinction of external vs. command-based modification is important so the SDK can\nmaintain determinism when using the command-based approach.\n - EVENT_TYPE_ACTIVITY_PROPERTIES_MODIFIED_EXTERNALLY: Some property or properties of an already-scheduled activity have changed by non-workflow code.\nThe distinction of external vs. command-based modification is important so the SDK can\nmaintain determinism when using the command-based approach.\n - EVENT_TYPE_WORKFLOW_PROPERTIES_MODIFIED: Workflow properties modified by user workflow code\n - EVENT_TYPE_NEXUS_OPERATION_SCHEDULED: A Nexus operation was scheduled using a ScheduleNexusOperation command.\n - EVENT_TYPE_NEXUS_OPERATION_STARTED: An asynchronous Nexus operation was started by a Nexus handler.\n - EVENT_TYPE_NEXUS_OPERATION_COMPLETED: A Nexus operation completed successfully.\n - EVENT_TYPE_NEXUS_OPERATION_FAILED: A Nexus operation failed.\n - EVENT_TYPE_NEXUS_OPERATION_CANCELED: A Nexus operation completed as canceled.\n - EVENT_TYPE_NEXUS_OPERATION_TIMED_OUT: A Nexus operation timed out.\n - EVENT_TYPE_NEXUS_OPERATION_CANCEL_REQUESTED: A Nexus operation was requested to be canceled using a RequestCancelNexusOperation command.\n - EVENT_TYPE_WORKFLOW_EXECUTION_OPTIONS_UPDATED: Workflow execution options updated by user.\n - EVENT_TYPE_NEXUS_OPERATION_CANCEL_REQUEST_COMPLETED: A cancellation request for a Nexus operation was successfully delivered to the Nexus handler.\n - EVENT_TYPE_NEXUS_OPERATION_CANCEL_REQUEST_FAILED: A cancellation request for a Nexus operation resulted in an error.\n - EVENT_TYPE_WORKFLOW_EXECUTION_PAUSED: An event that indicates that the workflow execution has been paused.\n - EVENT_TYPE_WORKFLOW_EXECUTION_UNPAUSED: An event that indicates that the previously paused workflow execution has been unpaused.\n - EVENT_TYPE_WORKFLOW_EXECUTION_TIME_SKIPPING_TRANSITIONED: An event that indicates time skipping advanced time or was disabled automatically after a bound was reached.\n - EVENT_TYPE_WORKFLOW_STREAM_SUBSCRIBED: A Workflow subscribed to a stream. Recorded once per subscription, not\nper message: the offsets a task consumed ride WorkflowTaskCompleted and\nthe payloads never enter History at all.\n - EVENT_TYPE_WORKFLOW_STREAM_MESSAGES_ADDED: A Workflow published a batch of messages to a stream. Recorded per\nbatch, and carrying only the offset range it landed at: the bodies go to\nthe stream's own log, never into History.", "title": "Whenever this list of events is changed do change the function shouldBufferEvent in mutableStateBuilder.go to make sure to do the correct event ordering" }, "v1Execution": { @@ -16786,6 +16788,12 @@ }, "workflowExecutionTimeSkippingTransitionedEventAttributes": { "$ref": "#/definitions/v1WorkflowExecutionTimeSkippingTransitionedEventAttributes" + }, + "workflowStreamSubscribedEventAttributes": { + "$ref": "#/definitions/v1WorkflowStreamSubscribedEventAttributes" + }, + "workflowStreamMessagesAddedEventAttributes": { + "$ref": "#/definitions/v1WorkflowStreamMessagesAddedEventAttributes" } }, "description": "History events are the method by which Temporal SDKs advance (or recreate) workflow state.\nSee the `EventType` enum for more info about what each event is for." @@ -18560,6 +18568,14 @@ "pollerGroupsInfo": { "$ref": "#/definitions/v1PollerGroupsInfo", "description": "The weighted, versioned list of poller groups IDs that client should use for future polls to\nthis task queue. Client should ignore this if it has already applied a snapshot with a\nversion greater than or equal to `poller_groups_info.version`. Client is expected to:\n 1. Maintain minimum number of pollers no less than the number of groups.\n 2. Try to assign the next poll to a group without any pending polls,\n 3. If every group has some pending polls, assign the next poll to a group randomly\n according to the weights." + }, + "streamSlices": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1StreamSlice" + }, + "description": "Stream data attached to this task. Delivered out of band so the payloads\nnever enter History; only the offset ranges are recorded there." } } }, @@ -20049,6 +20065,78 @@ } } }, + "v1StreamCursor": { + "type": "object", + "properties": { + "streamId": { + "type": "string" + }, + "fromOffset": { + "type": "string", + "format": "int64" + }, + "toOffset": { + "type": "string", + "format": "int64" + } + }, + "description": "The offsets a Workflow Task consumed, without the payloads. Recorded on\nWorkflowTaskCompleted so History grows with Workflow Tasks rather than with\nmessages." + }, + "v1StreamMessage": { + "type": "object", + "properties": { + "body": { + "$ref": "#/definitions/v1Payload" + }, + "metadata": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/v1Payload" + } + }, + "topic": { + "type": "string" + }, + "topicSequence": { + "type": "string", + "format": "int64" + } + } + }, + "v1StreamSlice": { + "type": "object", + "properties": { + "streamId": { + "type": "string" + }, + "runId": { + "type": "string" + }, + "fromOffset": { + "type": "string", + "format": "int64", + "description": "Inclusive." + }, + "toOffset": { + "type": "string", + "format": "int64", + "description": "Exclusive. Equal to from_offset when the subscription observed nothing,\nwhich is a fact replay has to reproduce rather than an absence of one." + }, + "messages": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1StreamMessage" + } + }, + "workflowTaskCompletedEventId": { + "type": "string", + "format": "int64", + "description": "The WorkflowTaskCompleted event whose stream_cursors recorded this range.\nSet only when the server is re-supplying a range for a task being\nreplayed; a slice for the task now being started leaves it unset, because\nthe event closing that task does not exist yet.\n\nReplay needs this because a Workflow Task response carries one slice set\nwhile a cache miss replays every prior task, so the ranges have to be\nmatched to the events that recorded them rather than to the response." + } + }, + "description": "A contiguous range of a stream delivered to a Workflow Task, along with the\noffsets it covers. The offsets are what History records; the messages\nthemselves are never written to History." + }, "v1StructuredCalendarSpec": { "type": "object", "properties": { @@ -22425,6 +22513,49 @@ } } }, + "v1WorkflowStreamMessagesAddedEventAttributes": { + "type": "object", + "properties": { + "workflowTaskCompletedEventId": { + "type": "string", + "format": "int64", + "description": "The WorkflowTaskCompleted event of the task whose command published this\nbatch." + }, + "streamId": { + "type": "string", + "description": "Stream the Workflow published to." + }, + "firstOffset": { + "type": "string", + "format": "int64", + "description": "Offset the first message of the batch landed at." + }, + "messageCount": { + "type": "string", + "format": "int64", + "description": "How many messages the batch held. With first_offset this names the range\nwithout carrying any of it, which is what keeps this event a fixed size\nno matter how large the batch or its payloads are." + } + } + }, + "v1WorkflowStreamSubscribedEventAttributes": { + "type": "object", + "properties": { + "workflowTaskCompletedEventId": { + "type": "string", + "format": "int64", + "description": "The WorkflowTaskCompleted event of the task whose command created this\nsubscription." + }, + "streamId": { + "type": "string", + "description": "Stream the Workflow subscribed to." + }, + "startOffset": { + "type": "string", + "format": "int64", + "description": "The offset the subscription actually starts from. Resolved by the server\nwhen the subscription is registered and recorded here, so replay reads\nthe resolved value rather than resolving it again against a stream that\nhas since moved." + } + } + }, "v1WorkflowTaskCompletedEventAttributes": { "type": "object", "properties": { @@ -22466,6 +22597,14 @@ "$ref": "#/definitions/v1VersioningBehavior", "description": "Versioning behavior sent by the worker that completed this task for this particular workflow\nexecution. UNSPECIFIED means the task was completed by an unversioned worker. This value\nupdates workflow execution's `versioning_info.behavior`." }, + "streamCursors": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1StreamCursor" + }, + "description": "Offset ranges this Workflow Task consumed from streams it subscribes to.\nRecorded on every task where a subscription is active, including when it\nobserved nothing: an empty range is a fact replay must reproduce, and\nomitting it would let replay deliver messages the Workflow did not have." + }, "workerDeploymentVersion": { "type": "string", "description": "The Worker Deployment Version that completed this task. Must be set if `versioning_behavior`\nis set. This value updates workflow execution's `versioning_info.version`.\nDeprecated. Replaced with `deployment_version`." diff --git a/openapi/openapiv3.yaml b/openapi/openapiv3.yaml index 2aa7c45bf..45d644b78 100644 --- a/openapi/openapiv3.yaml +++ b/openapi/openapiv3.yaml @@ -12878,6 +12878,8 @@ components: - EVENT_TYPE_WORKFLOW_EXECUTION_PAUSED - EVENT_TYPE_WORKFLOW_EXECUTION_UNPAUSED - EVENT_TYPE_WORKFLOW_EXECUTION_TIME_SKIPPING_TRANSITIONED + - EVENT_TYPE_WORKFLOW_STREAM_SUBSCRIBED + - EVENT_TYPE_WORKFLOW_STREAM_MESSAGES_ADDED type: string format: enum version: @@ -13043,6 +13045,10 @@ components: $ref: '#/components/schemas/WorkflowExecutionUnpausedEventAttributes' workflowExecutionTimeSkippingTransitionedEventAttributes: $ref: '#/components/schemas/WorkflowExecutionTimeSkippingTransitionedEventAttributes' + workflowStreamSubscribedEventAttributes: + $ref: '#/components/schemas/WorkflowStreamSubscribedEventAttributes' + workflowStreamMessagesAddedEventAttributes: + $ref: '#/components/schemas/WorkflowStreamMessagesAddedEventAttributes' description: |- History events are the method by which Temporal SDKs advance (or recreate) workflow state. See the `EventType` enum for more info about what each event is for. @@ -14853,6 +14859,13 @@ components: 2. Try to assign the next poll to a group without any pending polls, 3. If every group has some pending polls, assign the next poll to a group randomly according to the weights. + streamSlices: + type: array + items: + $ref: '#/components/schemas/StreamSlice' + description: |- + Stream data attached to this task. Delivered out of band so the payloads + never enter History; only the offset ranges are recorded there. PollerGroupInfo: type: object properties: @@ -15529,6 +15542,8 @@ components: - EVENT_TYPE_WORKFLOW_EXECUTION_PAUSED - EVENT_TYPE_WORKFLOW_EXECUTION_UNPAUSED - EVENT_TYPE_WORKFLOW_EXECUTION_TIME_SKIPPING_TRANSITIONED + - EVENT_TYPE_WORKFLOW_STREAM_SUBSCRIBED + - EVENT_TYPE_WORKFLOW_STREAM_MESSAGES_ADDED type: string description: The event type of the history event generated by the request. format: enum @@ -17680,6 +17695,66 @@ components: type: type: string description: The type of the driver, required. + StreamCursor: + type: object + properties: + streamId: + type: string + fromOffset: + type: string + toOffset: + type: string + description: |- + The offsets a Workflow Task consumed, without the payloads. Recorded on + WorkflowTaskCompleted so History grows with Workflow Tasks rather than with + messages. + StreamMessage: + type: object + properties: + body: + $ref: '#/components/schemas/Payload' + metadata: + type: object + additionalProperties: + $ref: '#/components/schemas/Payload' + topic: + type: string + topicSequence: + type: string + StreamSlice: + type: object + properties: + streamId: + type: string + runId: + type: string + fromOffset: + type: string + description: Inclusive. + toOffset: + type: string + description: |- + Exclusive. Equal to from_offset when the subscription observed nothing, + which is a fact replay has to reproduce rather than an absence of one. + messages: + type: array + items: + $ref: '#/components/schemas/StreamMessage' + workflowTaskCompletedEventId: + type: string + description: |- + The WorkflowTaskCompleted event whose stream_cursors recorded this range. + Set only when the server is re-supplying a range for a task being + replayed; a slice for the task now being started leaves it unset, because + the event closing that task does not exist yet. + + Replay needs this because a Workflow Task response carries one slice set + while a cache miss replays every prior task, so the ranges have to be + matched to the events that recorded them rather than to the response. + description: |- + A contiguous range of a stream delivered to a Workflow Task, along with the + offsets it covers. The offsets are what History records; the messages + themselves are never written to History. StructuredCalendarSpec: type: object properties: @@ -19830,6 +19905,8 @@ components: - EVENT_TYPE_WORKFLOW_EXECUTION_PAUSED - EVENT_TYPE_WORKFLOW_EXECUTION_UNPAUSED - EVENT_TYPE_WORKFLOW_EXECUTION_TIME_SKIPPING_TRANSITIONED + - EVENT_TYPE_WORKFLOW_STREAM_SUBSCRIBED + - EVENT_TYPE_WORKFLOW_STREAM_MESSAGES_ADDED type: string format: enum description: EventReference is a direct reference to a history event through the event ID. @@ -19901,6 +19978,8 @@ components: - EVENT_TYPE_WORKFLOW_EXECUTION_PAUSED - EVENT_TYPE_WORKFLOW_EXECUTION_UNPAUSED - EVENT_TYPE_WORKFLOW_EXECUTION_TIME_SKIPPING_TRANSITIONED + - EVENT_TYPE_WORKFLOW_STREAM_SUBSCRIBED + - EVENT_TYPE_WORKFLOW_STREAM_MESSAGES_ADDED type: string format: enum description: RequestIdReference is a indirect reference to a history event through the request ID. @@ -21023,6 +21102,44 @@ components: * BETWEEN ... AND STARTS_WITH description: Activity trigger will be triggered when an activity is about to start. + WorkflowStreamMessagesAddedEventAttributes: + type: object + properties: + workflowTaskCompletedEventId: + type: string + description: |- + The WorkflowTaskCompleted event of the task whose command published this + batch. + streamId: + type: string + description: Stream the Workflow published to. + firstOffset: + type: string + description: Offset the first message of the batch landed at. + messageCount: + type: string + description: |- + How many messages the batch held. With first_offset this names the range + without carrying any of it, which is what keeps this event a fixed size + no matter how large the batch or its payloads are. + WorkflowStreamSubscribedEventAttributes: + type: object + properties: + workflowTaskCompletedEventId: + type: string + description: |- + The WorkflowTaskCompleted event of the task whose command created this + subscription. + streamId: + type: string + description: Stream the Workflow subscribed to. + startOffset: + type: string + description: |- + The offset the subscription actually starts from. Resolved by the server + when the subscription is registered and recorded here, so replay reads + the resolved value rather than resolving it again against a stream that + has since moved. WorkflowTaskCompletedEventAttributes: type: object properties: @@ -21077,6 +21194,15 @@ components: execution. UNSPECIFIED means the task was completed by an unversioned worker. This value updates workflow execution's `versioning_info.behavior`. format: enum + streamCursors: + type: array + items: + $ref: '#/components/schemas/StreamCursor' + description: |- + Offset ranges this Workflow Task consumed from streams it subscribes to. + Recorded on every task where a subscription is active, including when it + observed nothing: an empty range is a fact replay must reproduce, and + omitting it would let replay deliver messages the Workflow did not have. workerDeploymentVersion: type: string description: |- From e65008a03349ae574c25f6dc823f8e2e06096dc8 Mon Sep 17 00:00:00 2001 From: Mohammad Dashti Date: Fri, 18 Sep 2026 16:27:48 -0700 Subject: [PATCH 4/9] Added workflow task failure causes for the stream commands. The server fails the task instead of the RPC when a stream command is rejected or a recorded range cannot be served, and needs causes the SDK can show. --- temporal/api/enums/v1/failed_cause.proto | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/temporal/api/enums/v1/failed_cause.proto b/temporal/api/enums/v1/failed_cause.proto index f902aa9a1..989febb8e 100644 --- a/temporal/api/enums/v1/failed_cause.proto +++ b/temporal/api/enums/v1/failed_cause.proto @@ -90,6 +90,14 @@ enum WorkflowTaskFailedCause { WORKFLOW_TASK_FAILED_CAUSE_WORKFLOW_PAUSE_REQUESTED_BEFORE_TASK_STARTED = 39; // A workflow task failed because the request exceeded a size limit. WORKFLOW_TASK_FAILED_CAUSE_REQUEST_TOO_LARGE = 40; + // A workflow task completed with an invalid AddStreamMessages command. + WORKFLOW_TASK_FAILED_CAUSE_BAD_ADD_STREAM_MESSAGES_ATTRIBUTES = 41; + // A workflow task completed with an invalid SubscribeStream command. + WORKFLOW_TASK_FAILED_CAUSE_BAD_SUBSCRIBE_STREAM_ATTRIBUTES = 42; + // A workflow task could not be started because a stream range it consumed and recorded in + // History can no longer be served, for example after truncation or because it exceeds the + // replay bound. Check the workflow task failure message for more information. + WORKFLOW_TASK_FAILED_CAUSE_STREAM_RANGE_UNAVAILABLE = 43; } // Activity tasks can fail for various reasons. Note that some of these reasons can only originate From 228b478636ee4d4a8a4b454f8230057a636698a3 Mon Sep 17 00:00:00 2001 From: Mohammad Dashti Date: Fri, 18 Sep 2026 16:27:48 -0700 Subject: [PATCH 5/9] Documented the stream proto fields and relocated stream_cursors. The publish command comment claimed no event. The run id, message fields and name precedence had no comments. --- temporal/api/command/v1/message.proto | 6 +++++- temporal/api/history/v1/message.proto | 13 +++++++------ temporal/api/stream/v1/message.proto | 7 +++++++ 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/temporal/api/command/v1/message.proto b/temporal/api/command/v1/message.proto index 311b918e4..4e848ece2 100644 --- a/temporal/api/command/v1/message.proto +++ b/temporal/api/command/v1/message.proto @@ -331,7 +331,8 @@ message Command { } // Appends to a stream the Workflow owns. Applied inside the Workflow Task's own -// commit, so it emits no History Event and does not schedule further work. +// commit. Produces one `WorkflowStreamMessagesAdded` event carrying the offset +// range and none of the payload; it schedules no further work. message AddStreamMessagesCommandAttributes { // Empty means the Workflow's default output stream. string stream_id = 1; @@ -347,6 +348,9 @@ message AddStreamMessagesCommandAttributes { message SubscribeStreamCommandAttributes { // Stream to consume. A stream in another execution is addressed by its id; // one this Workflow owns is addressed by the name it was published under. + // The server resolves an owned name first and falls back to a standalone + // id, so a Workflow that owns a stream under this name cannot reach a + // standalone stream with the same id. string stream_id = 1; // Where to start. Negative means from wherever the stream is when the // subscription is registered, which the server resolves and records so diff --git a/temporal/api/history/v1/message.proto b/temporal/api/history/v1/message.proto index 089dccf78..11023509e 100644 --- a/temporal/api/history/v1/message.proto +++ b/temporal/api/history/v1/message.proto @@ -370,12 +370,6 @@ message WorkflowTaskCompletedEventAttributes { // execution. UNSPECIFIED means the task was completed by an unversioned worker. This value // updates workflow execution's `versioning_info.behavior`. temporal.api.enums.v1.VersioningBehavior versioning_behavior = 8; - - // Offset ranges this Workflow Task consumed from streams it subscribes to. - // Recorded on every task where a subscription is active, including when it - // observed nothing: an empty range is a fact replay must reproduce, and - // omitting it would let replay deliver messages the Workflow did not have. - repeated temporal.api.stream.v1.StreamCursor stream_cursors = 20; // The Worker Deployment Version that completed this task. Must be set if `versioning_behavior` // is set. This value updates workflow execution's `versioning_info.version`. // Deprecated. Replaced with `deployment_version`. @@ -386,6 +380,13 @@ message WorkflowTaskCompletedEventAttributes { // The Worker Deployment Version that completed this task. Must be set if `versioning_behavior` // is set. This value updates workflow execution's `versioning_info.deployment_version`. temporal.api.deployment.v1.WorkerDeploymentVersion deployment_version = 11; + + // Offset ranges this Workflow Task consumed from streams it subscribes to. + // Recorded on every task where a subscription is active, including when it + // observed nothing: an empty range is a fact replay must reproduce, and + // omitting it would let replay deliver messages the Workflow did not have. + // Numbered 20 to leave 14 through 19 free for fields added on the main line. + repeated temporal.api.stream.v1.StreamCursor stream_cursors = 20; } message WorkflowTaskTimedOutEventAttributes { diff --git a/temporal/api/stream/v1/message.proto b/temporal/api/stream/v1/message.proto index a1702e3c7..396510f5e 100644 --- a/temporal/api/stream/v1/message.proto +++ b/temporal/api/stream/v1/message.proto @@ -12,9 +12,14 @@ option csharp_namespace = "Temporalio.Api.Stream.V1"; import "temporal/api/common/v1/message.proto"; message StreamMessage { + // The message itself, stored as sent. temporal.api.common.v1.Payload body = 1; + // Producer-supplied provenance, stored as sent. map metadata = 2; + // Producer-supplied grouping label, stored as sent. string topic = 3; + // Producer-supplied position within `topic`. The server stores it as sent + // and does not assign, validate or order by it. int64 topic_sequence = 4; } @@ -23,6 +28,8 @@ message StreamMessage { // themselves are never written to History. message StreamSlice { string stream_id = 1; + // Run id of the execution that owns the stream. Set on both a slice for the + // task being started and a re-supplied one. string run_id = 2; // Inclusive. int64 from_offset = 3; From 1aace128a29293181e0a324e5904f80797bc7b43 Mon Sep 17 00:00:00 2001 From: Mohammad Dashti Date: Fri, 18 Sep 2026 16:27:48 -0700 Subject: [PATCH 6/9] Regenerated the OpenAPI specs. --- openapi/openapiv2.json | 38 +++++++++++++++++++++++--------------- openapi/openapiv3.yaml | 34 ++++++++++++++++++++++++---------- 2 files changed, 47 insertions(+), 25 deletions(-) diff --git a/openapi/openapiv2.json b/openapi/openapiv2.json index 541226bd6..599bb39f1 100644 --- a/openapi/openapiv2.json +++ b/openapi/openapiv2.json @@ -20086,20 +20086,24 @@ "type": "object", "properties": { "body": { - "$ref": "#/definitions/v1Payload" + "$ref": "#/definitions/v1Payload", + "description": "The message itself, stored as sent." }, "metadata": { "type": "object", "additionalProperties": { "$ref": "#/definitions/v1Payload" - } + }, + "description": "Producer-supplied provenance, stored as sent." }, "topic": { - "type": "string" + "type": "string", + "description": "Producer-supplied grouping label, stored as sent." }, "topicSequence": { "type": "string", - "format": "int64" + "format": "int64", + "description": "Producer-supplied position within `topic`. The server stores it as sent\nand does not assign, validate or order by it." } } }, @@ -20110,7 +20114,8 @@ "type": "string" }, "runId": { - "type": "string" + "type": "string", + "description": "Run id of the execution that owns the stream. Set on both a slice for the\ntask being started and a re-supplied one." }, "fromOffset": { "type": "string", @@ -22597,14 +22602,6 @@ "$ref": "#/definitions/v1VersioningBehavior", "description": "Versioning behavior sent by the worker that completed this task for this particular workflow\nexecution. UNSPECIFIED means the task was completed by an unversioned worker. This value\nupdates workflow execution's `versioning_info.behavior`." }, - "streamCursors": { - "type": "array", - "items": { - "type": "object", - "$ref": "#/definitions/v1StreamCursor" - }, - "description": "Offset ranges this Workflow Task consumed from streams it subscribes to.\nRecorded on every task where a subscription is active, including when it\nobserved nothing: an empty range is a fact replay must reproduce, and\nomitting it would let replay deliver messages the Workflow did not have." - }, "workerDeploymentVersion": { "type": "string", "description": "The Worker Deployment Version that completed this task. Must be set if `versioning_behavior`\nis set. This value updates workflow execution's `versioning_info.version`.\nDeprecated. Replaced with `deployment_version`." @@ -22616,6 +22613,14 @@ "deploymentVersion": { "$ref": "#/definitions/v1WorkerDeploymentVersion", "description": "The Worker Deployment Version that completed this task. Must be set if `versioning_behavior`\nis set. This value updates workflow execution's `versioning_info.deployment_version`." + }, + "streamCursors": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1StreamCursor" + }, + "description": "Offset ranges this Workflow Task consumed from streams it subscribes to.\nRecorded on every task where a subscription is active, including when it\nobserved nothing: an empty range is a fact replay must reproduce, and\nomitting it would let replay deliver messages the Workflow did not have.\nNumbered 20 to leave 14 through 19 free for fields added on the main line." } } }, @@ -22692,10 +22697,13 @@ "WORKFLOW_TASK_FAILED_CAUSE_PAYLOADS_TOO_LARGE", "WORKFLOW_TASK_FAILED_CAUSE_EXTERNAL_STORAGE_FAILURE", "WORKFLOW_TASK_FAILED_CAUSE_WORKFLOW_PAUSE_REQUESTED_BEFORE_TASK_STARTED", - "WORKFLOW_TASK_FAILED_CAUSE_REQUEST_TOO_LARGE" + "WORKFLOW_TASK_FAILED_CAUSE_REQUEST_TOO_LARGE", + "WORKFLOW_TASK_FAILED_CAUSE_BAD_ADD_STREAM_MESSAGES_ATTRIBUTES", + "WORKFLOW_TASK_FAILED_CAUSE_BAD_SUBSCRIBE_STREAM_ATTRIBUTES", + "WORKFLOW_TASK_FAILED_CAUSE_STREAM_RANGE_UNAVAILABLE" ], "default": "WORKFLOW_TASK_FAILED_CAUSE_UNSPECIFIED", - "description": "Workflow tasks can fail for various reasons. Note that some of these reasons can only originate\nfrom the server, and some of them can only originate from the SDK/worker.\n\n - WORKFLOW_TASK_FAILED_CAUSE_UNHANDLED_COMMAND: Between starting and completing the workflow task (with a workflow completion command), some\nnew command (like a signal) was processed into workflow history. The outstanding task will be\nfailed with this reason, and a worker must pick up a new task.\n - WORKFLOW_TASK_FAILED_CAUSE_RESET_STICKY_TASK_QUEUE: The worker wishes to fail the task and have the next one be generated on a normal, not sticky\nqueue. Generally workers should prefer to use the explicit `ResetStickyTaskQueue` RPC call.\n - WORKFLOW_TASK_FAILED_CAUSE_NON_DETERMINISTIC_ERROR: The worker encountered a mismatch while replaying history between what was expected, and\nwhat the workflow code actually did.\n - WORKFLOW_TASK_FAILED_CAUSE_PENDING_CHILD_WORKFLOWS_LIMIT_EXCEEDED: We send the below error codes to users when their requests would violate a size constraint\nof their workflow. We do this to ensure that the state of their workflow does not become too\nlarge because that can cause severe performance degradation. You can modify the thresholds for\neach of these errors within your dynamic config.\n\nSpawning a new child workflow would cause this workflow to exceed its limit of pending child\nworkflows.\n - WORKFLOW_TASK_FAILED_CAUSE_PENDING_ACTIVITIES_LIMIT_EXCEEDED: Starting a new activity would cause this workflow to exceed its limit of pending activities\nthat we track.\n - WORKFLOW_TASK_FAILED_CAUSE_PENDING_SIGNALS_LIMIT_EXCEEDED: A workflow has a buffer of signals that have not yet reached their destination. We return this\nerror when sending a new signal would exceed the capacity of this buffer.\n - WORKFLOW_TASK_FAILED_CAUSE_PENDING_REQUEST_CANCEL_LIMIT_EXCEEDED: Similarly, we have a buffer of pending requests to cancel other workflows. We return this error\nwhen our capacity for pending cancel requests is already reached.\n - WORKFLOW_TASK_FAILED_CAUSE_BAD_UPDATE_WORKFLOW_EXECUTION_MESSAGE: Workflow execution update message (update.Acceptance, update.Rejection, or update.Response)\nhas wrong format, or missing required fields.\n - WORKFLOW_TASK_FAILED_CAUSE_UNHANDLED_UPDATE: Similar to WORKFLOW_TASK_FAILED_CAUSE_UNHANDLED_COMMAND, but for updates.\n - WORKFLOW_TASK_FAILED_CAUSE_BAD_SCHEDULE_NEXUS_OPERATION_ATTRIBUTES: A workflow task completed with an invalid ScheduleNexusOperation command.\n - WORKFLOW_TASK_FAILED_CAUSE_PENDING_NEXUS_OPERATIONS_LIMIT_EXCEEDED: A workflow task completed requesting to schedule a Nexus Operation exceeding the server configured limit.\n - WORKFLOW_TASK_FAILED_CAUSE_BAD_REQUEST_CANCEL_NEXUS_OPERATION_ATTRIBUTES: A workflow task completed with an invalid RequestCancelNexusOperation command.\n - WORKFLOW_TASK_FAILED_CAUSE_FEATURE_DISABLED: A workflow task completed requesting a feature that's disabled on the server (either system wide or - typically -\nfor the workflow's namespace).\nCheck the workflow task failure message for more information.\n - WORKFLOW_TASK_FAILED_CAUSE_GRPC_MESSAGE_TOO_LARGE: A workflow task failed because a grpc message was too large.\n - WORKFLOW_TASK_FAILED_CAUSE_PAYLOADS_TOO_LARGE: A workflow task failed because payloads were too large.\n - WORKFLOW_TASK_FAILED_CAUSE_EXTERNAL_STORAGE_FAILURE: A workflow task failed because an external storage operation failed.\nCheck the workflow task failure message for more information.\n - WORKFLOW_TASK_FAILED_CAUSE_WORKFLOW_PAUSE_REQUESTED_BEFORE_TASK_STARTED: A workflow task is failed because the workflow is paused before the task is started.\n - WORKFLOW_TASK_FAILED_CAUSE_REQUEST_TOO_LARGE: A workflow task failed because the request exceeded a size limit." + "description": "Workflow tasks can fail for various reasons. Note that some of these reasons can only originate\nfrom the server, and some of them can only originate from the SDK/worker.\n\n - WORKFLOW_TASK_FAILED_CAUSE_UNHANDLED_COMMAND: Between starting and completing the workflow task (with a workflow completion command), some\nnew command (like a signal) was processed into workflow history. The outstanding task will be\nfailed with this reason, and a worker must pick up a new task.\n - WORKFLOW_TASK_FAILED_CAUSE_RESET_STICKY_TASK_QUEUE: The worker wishes to fail the task and have the next one be generated on a normal, not sticky\nqueue. Generally workers should prefer to use the explicit `ResetStickyTaskQueue` RPC call.\n - WORKFLOW_TASK_FAILED_CAUSE_NON_DETERMINISTIC_ERROR: The worker encountered a mismatch while replaying history between what was expected, and\nwhat the workflow code actually did.\n - WORKFLOW_TASK_FAILED_CAUSE_PENDING_CHILD_WORKFLOWS_LIMIT_EXCEEDED: We send the below error codes to users when their requests would violate a size constraint\nof their workflow. We do this to ensure that the state of their workflow does not become too\nlarge because that can cause severe performance degradation. You can modify the thresholds for\neach of these errors within your dynamic config.\n\nSpawning a new child workflow would cause this workflow to exceed its limit of pending child\nworkflows.\n - WORKFLOW_TASK_FAILED_CAUSE_PENDING_ACTIVITIES_LIMIT_EXCEEDED: Starting a new activity would cause this workflow to exceed its limit of pending activities\nthat we track.\n - WORKFLOW_TASK_FAILED_CAUSE_PENDING_SIGNALS_LIMIT_EXCEEDED: A workflow has a buffer of signals that have not yet reached their destination. We return this\nerror when sending a new signal would exceed the capacity of this buffer.\n - WORKFLOW_TASK_FAILED_CAUSE_PENDING_REQUEST_CANCEL_LIMIT_EXCEEDED: Similarly, we have a buffer of pending requests to cancel other workflows. We return this error\nwhen our capacity for pending cancel requests is already reached.\n - WORKFLOW_TASK_FAILED_CAUSE_BAD_UPDATE_WORKFLOW_EXECUTION_MESSAGE: Workflow execution update message (update.Acceptance, update.Rejection, or update.Response)\nhas wrong format, or missing required fields.\n - WORKFLOW_TASK_FAILED_CAUSE_UNHANDLED_UPDATE: Similar to WORKFLOW_TASK_FAILED_CAUSE_UNHANDLED_COMMAND, but for updates.\n - WORKFLOW_TASK_FAILED_CAUSE_BAD_SCHEDULE_NEXUS_OPERATION_ATTRIBUTES: A workflow task completed with an invalid ScheduleNexusOperation command.\n - WORKFLOW_TASK_FAILED_CAUSE_PENDING_NEXUS_OPERATIONS_LIMIT_EXCEEDED: A workflow task completed requesting to schedule a Nexus Operation exceeding the server configured limit.\n - WORKFLOW_TASK_FAILED_CAUSE_BAD_REQUEST_CANCEL_NEXUS_OPERATION_ATTRIBUTES: A workflow task completed with an invalid RequestCancelNexusOperation command.\n - WORKFLOW_TASK_FAILED_CAUSE_FEATURE_DISABLED: A workflow task completed requesting a feature that's disabled on the server (either system wide or - typically -\nfor the workflow's namespace).\nCheck the workflow task failure message for more information.\n - WORKFLOW_TASK_FAILED_CAUSE_GRPC_MESSAGE_TOO_LARGE: A workflow task failed because a grpc message was too large.\n - WORKFLOW_TASK_FAILED_CAUSE_PAYLOADS_TOO_LARGE: A workflow task failed because payloads were too large.\n - WORKFLOW_TASK_FAILED_CAUSE_EXTERNAL_STORAGE_FAILURE: A workflow task failed because an external storage operation failed.\nCheck the workflow task failure message for more information.\n - WORKFLOW_TASK_FAILED_CAUSE_WORKFLOW_PAUSE_REQUESTED_BEFORE_TASK_STARTED: A workflow task is failed because the workflow is paused before the task is started.\n - WORKFLOW_TASK_FAILED_CAUSE_REQUEST_TOO_LARGE: A workflow task failed because the request exceeded a size limit.\n - WORKFLOW_TASK_FAILED_CAUSE_BAD_ADD_STREAM_MESSAGES_ATTRIBUTES: A workflow task completed with an invalid AddStreamMessages command.\n - WORKFLOW_TASK_FAILED_CAUSE_BAD_SUBSCRIBE_STREAM_ATTRIBUTES: A workflow task completed with an invalid SubscribeStream command.\n - WORKFLOW_TASK_FAILED_CAUSE_STREAM_RANGE_UNAVAILABLE: A workflow task could not be started because a stream range it consumed and recorded in\nHistory can no longer be served, for example after truncation or because it exceeds the\nreplay bound. Check the workflow task failure message for more information." }, "v1WorkflowTaskFailedEventAttributes": { "type": "object", diff --git a/openapi/openapiv3.yaml b/openapi/openapiv3.yaml index 45d644b78..92c4b24f1 100644 --- a/openapi/openapiv3.yaml +++ b/openapi/openapiv3.yaml @@ -17712,15 +17712,22 @@ components: type: object properties: body: - $ref: '#/components/schemas/Payload' + allOf: + - $ref: '#/components/schemas/Payload' + description: The message itself, stored as sent. metadata: type: object additionalProperties: $ref: '#/components/schemas/Payload' + description: Producer-supplied provenance, stored as sent. topic: type: string + description: Producer-supplied grouping label, stored as sent. topicSequence: type: string + description: |- + Producer-supplied position within `topic`. The server stores it as sent + and does not assign, validate or order by it. StreamSlice: type: object properties: @@ -17728,6 +17735,9 @@ components: type: string runId: type: string + description: |- + Run id of the execution that owns the stream. Set on both a slice for the + task being started and a re-supplied one. fromOffset: type: string description: Inclusive. @@ -21194,15 +21204,6 @@ components: execution. UNSPECIFIED means the task was completed by an unversioned worker. This value updates workflow execution's `versioning_info.behavior`. format: enum - streamCursors: - type: array - items: - $ref: '#/components/schemas/StreamCursor' - description: |- - Offset ranges this Workflow Task consumed from streams it subscribes to. - Recorded on every task where a subscription is active, including when it - observed nothing: an empty range is a fact replay must reproduce, and - omitting it would let replay deliver messages the Workflow did not have. workerDeploymentVersion: type: string description: |- @@ -21220,6 +21221,16 @@ components: description: |- The Worker Deployment Version that completed this task. Must be set if `versioning_behavior` is set. This value updates workflow execution's `versioning_info.deployment_version`. + streamCursors: + type: array + items: + $ref: '#/components/schemas/StreamCursor' + description: |- + Offset ranges this Workflow Task consumed from streams it subscribes to. + Recorded on every task where a subscription is active, including when it + observed nothing: an empty range is a fact replay must reproduce, and + omitting it would let replay deliver messages the Workflow did not have. + Numbered 20 to leave 14 through 19 free for fields added on the main line. WorkflowTaskCompletedMetadata: type: object properties: @@ -21327,6 +21338,9 @@ components: - WORKFLOW_TASK_FAILED_CAUSE_EXTERNAL_STORAGE_FAILURE - WORKFLOW_TASK_FAILED_CAUSE_WORKFLOW_PAUSE_REQUESTED_BEFORE_TASK_STARTED - WORKFLOW_TASK_FAILED_CAUSE_REQUEST_TOO_LARGE + - WORKFLOW_TASK_FAILED_CAUSE_BAD_ADD_STREAM_MESSAGES_ATTRIBUTES + - WORKFLOW_TASK_FAILED_CAUSE_BAD_SUBSCRIBE_STREAM_ATTRIBUTES + - WORKFLOW_TASK_FAILED_CAUSE_STREAM_RANGE_UNAVAILABLE type: string format: enum failure: From 43546df7f9949ba94b80cd9f7756af66a48654c6 Mon Sep 17 00:00:00 2001 From: Mohammad Dashti Date: Mon, 21 Sep 2026 01:22:58 -0700 Subject: [PATCH 7/9] Named the stream record on the wire and carried its producer identity. The record is the wire format every store keeps and every language reads, so it carries its kind, producer, attempt and sequence itself instead of a private envelope inside the body. The body is the user's payload, so a codec applies to it like to any other payload. --- temporal/api/command/v1/message.proto | 4 ++- temporal/api/stream/v1/message.proto | 48 ++++++++++++++++++++------- 2 files changed, 39 insertions(+), 13 deletions(-) diff --git a/temporal/api/command/v1/message.proto b/temporal/api/command/v1/message.proto index 4e848ece2..047c5e142 100644 --- a/temporal/api/command/v1/message.proto +++ b/temporal/api/command/v1/message.proto @@ -336,7 +336,9 @@ message Command { message AddStreamMessagesCommandAttributes { // Empty means the Workflow's default output stream. string stream_id = 1; - repeated temporal.api.stream.v1.StreamMessage messages = 2; + // Stored in order. The server sets `producer_id` to empty on each record, + // because the owning Workflow is the producer here. + repeated temporal.api.stream.v1.StreamRecord records = 2; } // Subscribe this Workflow to a stream, so later Workflow Tasks carry the ranges diff --git a/temporal/api/stream/v1/message.proto b/temporal/api/stream/v1/message.proto index 396510f5e..d470009e4 100644 --- a/temporal/api/stream/v1/message.proto +++ b/temporal/api/stream/v1/message.proto @@ -11,20 +11,30 @@ option csharp_namespace = "Temporalio.Api.Stream.V1"; import "temporal/api/common/v1/message.proto"; -message StreamMessage { - // The message itself, stored as sent. +// One entry in a stream. The record is the wire format: stores keep it +// serialized as is and readers in every language decode the same bytes. +message StreamRecord { + // The value the producer published, stored as sent. A payload codec + // applies here as it does to any other payload. temporal.api.common.v1.Payload body = 1; // Producer-supplied provenance, stored as sent. map metadata = 2; // Producer-supplied grouping label, stored as sent. string topic = 3; - // Producer-supplied position within `topic`. The server stores it as sent - // and does not assign, validate or order by it. - int64 topic_sequence = 4; + // How to read this record. Unspecified is read as DATA. + StreamRecordKind kind = 4; + // Who wrote the record. Empty when the owning Workflow did. + string producer_id = 5; + // The producer's attempt. Readers treat a later attempt by the same + // producer as superseding what the earlier one wrote. + int64 attempt = 6; + // The producer's position within its attempt, or -1 when unnumbered. + // Stored as sent; the server does not assign, validate or order by it. + int64 sequence = 7; } // A contiguous range of a stream delivered to a Workflow Task, along with the -// offsets it covers. The offsets are what History records; the messages +// offsets it covers. The offsets are what History records; the records // themselves are never written to History. message StreamSlice { string stream_id = 1; @@ -36,11 +46,11 @@ message StreamSlice { // Exclusive. Equal to from_offset when the subscription observed nothing, // which is a fact replay has to reproduce rather than an absence of one. int64 to_offset = 4; - repeated StreamMessage messages = 5; - // The WorkflowTaskCompleted event whose stream_cursors recorded this range. - // Set only when the server is re-supplying a range for a task being - // replayed; a slice for the task now being started leaves it unset, because - // the event closing that task does not exist yet. + repeated StreamRecord records = 5; + // The WorkflowTaskCompleted event whose stream_cursors recorded this + // range. Set only when the server is re-supplying a range for a task + // being replayed; a slice for the task now being started leaves it unset, + // because the event closing that task does not exist yet. // // Replay needs this because a Workflow Task response carries one slice set // while a cache miss replays every prior task, so the ranges have to be @@ -50,9 +60,23 @@ message StreamSlice { // The offsets a Workflow Task consumed, without the payloads. Recorded on // WorkflowTaskCompleted so History grows with Workflow Tasks rather than with -// messages. +// records. message StreamCursor { string stream_id = 1; + // Inclusive. int64 from_offset = 2; + // Exclusive. int64 to_offset = 3; } + +// What a record means to a reader. Kept on the record itself so every store +// and every language reads it the same way without a private envelope. +enum StreamRecordKind { + // Read as DATA. + STREAM_RECORD_KIND_UNSPECIFIED = 0; + // A value the producer published; `body` carries it. + STREAM_RECORD_KIND_DATA = 1; + // The producer named by `producer_id` writes nothing more on `topic`. + // Says nothing about that producer's outcome and does not end the stream. + STREAM_RECORD_KIND_FINISH = 2; +} From 5efc2779e1a955b0ff88cd754c4f44e0b0c44db5 Mon Sep 17 00:00:00 2001 From: Mohammad Dashti Date: Mon, 21 Sep 2026 01:23:08 -0700 Subject: [PATCH 8/9] Renamed the stream command, event and range to the record vocabulary. The SDKs call an entry a record and a cursor a single position, and `temporal.api` already uses "message" for protocol envelopes. One noun on the wire keeps History readable next to user code. --- api-linter.yaml | 2 +- temporal/api/command/v1/message.proto | 11 ++++++----- temporal/api/enums/v1/command_type.proto | 2 +- temporal/api/enums/v1/event_type.proto | 6 +++--- temporal/api/enums/v1/failed_cause.proto | 4 ++-- temporal/api/history/v1/message.proto | 18 +++++++++--------- temporal/api/stream/v1/message.proto | 6 +++--- 7 files changed, 25 insertions(+), 24 deletions(-) diff --git a/api-linter.yaml b/api-linter.yaml index 5a38d2b4c..7717df60e 100644 --- a/api-linter.yaml +++ b/api-linter.yaml @@ -15,7 +15,7 @@ - included_paths: - "**/stream/v1/message.proto" disabled_rules: - - "core::0140::prepositions" # Half-open offset ranges are spelled `from_offset`/`to_offset` here and in the server's own protos -- https://linter.aip.dev/140/prepositions + - "core::0140::prepositions" # Half-open offset ranges on StreamSlice and StreamRange are spelled `from_offset`/`to_offset`, as in the server's own protos -- https://linter.aip.dev/140/prepositions - included_paths: - "**/workflowservice/v1/request_response.proto" diff --git a/temporal/api/command/v1/message.proto b/temporal/api/command/v1/message.proto index 047c5e142..7d10e441b 100644 --- a/temporal/api/command/v1/message.proto +++ b/temporal/api/command/v1/message.proto @@ -325,15 +325,16 @@ message Command { ScheduleNexusOperationCommandAttributes schedule_nexus_operation_command_attributes = 18; RequestCancelNexusOperationCommandAttributes request_cancel_nexus_operation_command_attributes = 19; - AddStreamMessagesCommandAttributes add_stream_messages_command_attributes = 20; + AppendStreamRecordsCommandAttributes append_stream_records_command_attributes = 20; SubscribeStreamCommandAttributes subscribe_stream_command_attributes = 21; } } -// Appends to a stream the Workflow owns. Applied inside the Workflow Task's own -// commit. Produces one `WorkflowStreamMessagesAdded` event carrying the offset -// range and none of the payload; it schedules no further work. -message AddStreamMessagesCommandAttributes { +// Appends records to a stream the Workflow owns. Applied inside the Workflow +// Task's own commit. Produces one `WorkflowStreamRecordsAppended` event +// carrying the offset range and none of the payload; it schedules no further +// work. +message AppendStreamRecordsCommandAttributes { // Empty means the Workflow's default output stream. string stream_id = 1; // Stored in order. The server sets `producer_id` to empty on each record, diff --git a/temporal/api/enums/v1/command_type.proto b/temporal/api/enums/v1/command_type.proto index 677ed3b2d..967169b19 100644 --- a/temporal/api/enums/v1/command_type.proto +++ b/temporal/api/enums/v1/command_type.proto @@ -29,6 +29,6 @@ enum CommandType { COMMAND_TYPE_MODIFY_WORKFLOW_PROPERTIES = 16; COMMAND_TYPE_SCHEDULE_NEXUS_OPERATION = 17; COMMAND_TYPE_REQUEST_CANCEL_NEXUS_OPERATION = 18; - COMMAND_TYPE_ADD_STREAM_MESSAGES = 19; + COMMAND_TYPE_APPEND_STREAM_RECORDS = 19; COMMAND_TYPE_SUBSCRIBE_STREAM = 20; } diff --git a/temporal/api/enums/v1/event_type.proto b/temporal/api/enums/v1/event_type.proto index b515acb1d..a386b1db7 100644 --- a/temporal/api/enums/v1/event_type.proto +++ b/temporal/api/enums/v1/event_type.proto @@ -176,11 +176,11 @@ enum EventType { // An event that indicates time skipping advanced time or was disabled automatically after a bound was reached. EVENT_TYPE_WORKFLOW_EXECUTION_TIME_SKIPPING_TRANSITIONED = 60; // A Workflow subscribed to a stream. Recorded once per subscription, not - // per message: the offsets a task consumed ride WorkflowTaskCompleted and + // per record: the offsets a task consumed ride WorkflowTaskCompleted and // the payloads never enter History at all. EVENT_TYPE_WORKFLOW_STREAM_SUBSCRIBED = 61; - // A Workflow published a batch of messages to a stream. Recorded per + // A Workflow appended a batch of records to a stream. Recorded per // batch, and carrying only the offset range it landed at: the bodies go to // the stream's own log, never into History. - EVENT_TYPE_WORKFLOW_STREAM_MESSAGES_ADDED = 62; + EVENT_TYPE_WORKFLOW_STREAM_RECORDS_APPENDED = 62; } diff --git a/temporal/api/enums/v1/failed_cause.proto b/temporal/api/enums/v1/failed_cause.proto index 989febb8e..16f876a87 100644 --- a/temporal/api/enums/v1/failed_cause.proto +++ b/temporal/api/enums/v1/failed_cause.proto @@ -90,8 +90,8 @@ enum WorkflowTaskFailedCause { WORKFLOW_TASK_FAILED_CAUSE_WORKFLOW_PAUSE_REQUESTED_BEFORE_TASK_STARTED = 39; // A workflow task failed because the request exceeded a size limit. WORKFLOW_TASK_FAILED_CAUSE_REQUEST_TOO_LARGE = 40; - // A workflow task completed with an invalid AddStreamMessages command. - WORKFLOW_TASK_FAILED_CAUSE_BAD_ADD_STREAM_MESSAGES_ATTRIBUTES = 41; + // A workflow task completed with an invalid AppendStreamRecords command. + WORKFLOW_TASK_FAILED_CAUSE_BAD_APPEND_STREAM_RECORDS_ATTRIBUTES = 41; // A workflow task completed with an invalid SubscribeStream command. WORKFLOW_TASK_FAILED_CAUSE_BAD_SUBSCRIBE_STREAM_ATTRIBUTES = 42; // A workflow task could not be started because a stream range it consumed and recorded in diff --git a/temporal/api/history/v1/message.proto b/temporal/api/history/v1/message.proto index 11023509e..cf5f944fe 100644 --- a/temporal/api/history/v1/message.proto +++ b/temporal/api/history/v1/message.proto @@ -384,9 +384,9 @@ message WorkflowTaskCompletedEventAttributes { // Offset ranges this Workflow Task consumed from streams it subscribes to. // Recorded on every task where a subscription is active, including when it // observed nothing: an empty range is a fact replay must reproduce, and - // omitting it would let replay deliver messages the Workflow did not have. + // omitting it would let replay deliver records the Workflow did not have. // Numbered 20 to leave 14 through 19 free for fields added on the main line. - repeated temporal.api.stream.v1.StreamCursor stream_cursors = 20; + repeated temporal.api.stream.v1.StreamRange consumed_stream_ranges = 20; } message WorkflowTaskTimedOutEventAttributes { @@ -976,18 +976,18 @@ message WorkflowStreamSubscribedEventAttributes { int64 start_offset = 3; } -message WorkflowStreamMessagesAddedEventAttributes { - // The WorkflowTaskCompleted event of the task whose command published this +message WorkflowStreamRecordsAppendedEventAttributes { + // The WorkflowTaskCompleted event of the task whose command appended this // batch. int64 workflow_task_completed_event_id = 1; - // Stream the Workflow published to. + // Stream the Workflow appended to. string stream_id = 2; - // Offset the first message of the batch landed at. + // Offset the first record of the batch landed at. int64 first_offset = 3; - // How many messages the batch held. With first_offset this names the range + // How many records the batch held. With first_offset this names the range // without carrying any of it, which is what keeps this event a fixed size // no matter how large the batch or its payloads are. - int64 message_count = 4; + int64 record_count = 4; } message WorkflowExecutionUpdateAcceptedEventAttributes { @@ -1314,7 +1314,7 @@ message HistoryEvent { WorkflowExecutionUnpausedEventAttributes workflow_execution_unpaused_event_attributes = 64; WorkflowExecutionTimeSkippingTransitionedEventAttributes workflow_execution_time_skipping_transitioned_event_attributes = 65; WorkflowStreamSubscribedEventAttributes workflow_stream_subscribed_event_attributes = 66; - WorkflowStreamMessagesAddedEventAttributes workflow_stream_messages_added_event_attributes = 67; + WorkflowStreamRecordsAppendedEventAttributes workflow_stream_records_appended_event_attributes = 67; } } diff --git a/temporal/api/stream/v1/message.proto b/temporal/api/stream/v1/message.proto index d470009e4..9f0c88dfb 100644 --- a/temporal/api/stream/v1/message.proto +++ b/temporal/api/stream/v1/message.proto @@ -47,8 +47,8 @@ message StreamSlice { // which is a fact replay has to reproduce rather than an absence of one. int64 to_offset = 4; repeated StreamRecord records = 5; - // The WorkflowTaskCompleted event whose stream_cursors recorded this - // range. Set only when the server is re-supplying a range for a task + // The WorkflowTaskCompleted event whose consumed_stream_ranges recorded + // this range. Set only when the server is re-supplying a range for a task // being replayed; a slice for the task now being started leaves it unset, // because the event closing that task does not exist yet. // @@ -61,7 +61,7 @@ message StreamSlice { // The offsets a Workflow Task consumed, without the payloads. Recorded on // WorkflowTaskCompleted so History grows with Workflow Tasks rather than with // records. -message StreamCursor { +message StreamRange { string stream_id = 1; // Inclusive. int64 from_offset = 2; From 2cffd47fac0d62201cd26a128da4fb0b189b1977 Mon Sep 17 00:00:00 2001 From: Mohammad Dashti Date: Mon, 21 Sep 2026 01:23:09 -0700 Subject: [PATCH 9/9] Regenerated the OpenAPI specs. --- openapi/openapiv2.json | 82 +++++++++++++++++++++++++++-------------- openapi/openapiv3.yaml | 83 +++++++++++++++++++++++++++--------------- 2 files changed, 107 insertions(+), 58 deletions(-) diff --git a/openapi/openapiv2.json b/openapi/openapiv2.json index 599bb39f1..ec6248d92 100644 --- a/openapi/openapiv2.json +++ b/openapi/openapiv2.json @@ -16118,10 +16118,10 @@ "EVENT_TYPE_WORKFLOW_EXECUTION_UNPAUSED", "EVENT_TYPE_WORKFLOW_EXECUTION_TIME_SKIPPING_TRANSITIONED", "EVENT_TYPE_WORKFLOW_STREAM_SUBSCRIBED", - "EVENT_TYPE_WORKFLOW_STREAM_MESSAGES_ADDED" + "EVENT_TYPE_WORKFLOW_STREAM_RECORDS_APPENDED" ], "default": "EVENT_TYPE_UNSPECIFIED", - "description": "- EVENT_TYPE_UNSPECIFIED: Place holder and should never appear in a Workflow execution history\n - EVENT_TYPE_WORKFLOW_EXECUTION_STARTED: Workflow execution has been triggered/started\nIt contains Workflow execution inputs, as well as Workflow timeout configurations\n - EVENT_TYPE_WORKFLOW_EXECUTION_COMPLETED: Workflow execution has successfully completed and contains Workflow execution results\n - EVENT_TYPE_WORKFLOW_EXECUTION_FAILED: Workflow execution has unsuccessfully completed and contains the Workflow execution error\n - EVENT_TYPE_WORKFLOW_EXECUTION_TIMED_OUT: Workflow execution has timed out by the Temporal Server\nUsually due to the Workflow having not been completed within timeout settings\n - EVENT_TYPE_WORKFLOW_TASK_SCHEDULED: Workflow Task has been scheduled and the SDK client should now be able to process any new history events\n - EVENT_TYPE_WORKFLOW_TASK_STARTED: Workflow Task has started and the SDK client has picked up the Workflow Task and is processing new history events\n - EVENT_TYPE_WORKFLOW_TASK_COMPLETED: Workflow Task has completed\nThe SDK client picked up the Workflow Task and processed new history events\nSDK client may or may not ask the Temporal Server to do additional work, such as:\nEVENT_TYPE_ACTIVITY_TASK_SCHEDULED\nEVENT_TYPE_TIMER_STARTED\nEVENT_TYPE_UPSERT_WORKFLOW_SEARCH_ATTRIBUTES\nEVENT_TYPE_MARKER_RECORDED\nEVENT_TYPE_START_CHILD_WORKFLOW_EXECUTION_INITIATED\nEVENT_TYPE_REQUEST_CANCEL_EXTERNAL_WORKFLOW_EXECUTION_INITIATED\nEVENT_TYPE_SIGNAL_EXTERNAL_WORKFLOW_EXECUTION_INITIATED\nEVENT_TYPE_WORKFLOW_EXECUTION_COMPLETED\nEVENT_TYPE_WORKFLOW_EXECUTION_FAILED\nEVENT_TYPE_WORKFLOW_EXECUTION_CANCELED\nEVENT_TYPE_WORKFLOW_EXECUTION_CONTINUED_AS_NEW\n - EVENT_TYPE_WORKFLOW_TASK_TIMED_OUT: Workflow Task encountered a timeout\nEither an SDK client with a local cache was not available at the time, or it took too long for the SDK client to process the task\n - EVENT_TYPE_WORKFLOW_TASK_FAILED: Workflow Task encountered a failure\nUsually this means that the Workflow was non-deterministic\nHowever, the Workflow reset functionality also uses this event\n - EVENT_TYPE_ACTIVITY_TASK_SCHEDULED: Activity Task was scheduled\nThe SDK client should pick up this activity task and execute\nThis event type contains activity inputs, as well as activity timeout configurations\n - EVENT_TYPE_ACTIVITY_TASK_STARTED: Activity Task has started executing\nThe SDK client has picked up the Activity Task and is processing the Activity invocation\n - EVENT_TYPE_ACTIVITY_TASK_COMPLETED: Activity Task has finished successfully\nThe SDK client has picked up and successfully completed the Activity Task\nThis event type contains Activity execution results\n - EVENT_TYPE_ACTIVITY_TASK_FAILED: Activity Task has finished unsuccessfully\nThe SDK picked up the Activity Task but unsuccessfully completed it\nThis event type contains Activity execution errors\n - EVENT_TYPE_ACTIVITY_TASK_TIMED_OUT: Activity has timed out according to the Temporal Server\nActivity did not complete within the timeout settings\n - EVENT_TYPE_ACTIVITY_TASK_CANCEL_REQUESTED: A request to cancel the Activity has occurred\nThe SDK client will be able to confirm cancellation of an Activity during an Activity heartbeat\n - EVENT_TYPE_ACTIVITY_TASK_CANCELED: Activity has been cancelled\n - EVENT_TYPE_TIMER_STARTED: A timer has started\n - EVENT_TYPE_TIMER_FIRED: A timer has fired\n - EVENT_TYPE_TIMER_CANCELED: A time has been cancelled\n - EVENT_TYPE_WORKFLOW_EXECUTION_CANCEL_REQUESTED: A request has been made to cancel the Workflow execution\n - EVENT_TYPE_WORKFLOW_EXECUTION_CANCELED: SDK client has confirmed the cancellation request and the Workflow execution has been cancelled\n - EVENT_TYPE_REQUEST_CANCEL_EXTERNAL_WORKFLOW_EXECUTION_INITIATED: Workflow has requested that the Temporal Server try to cancel another Workflow\n - EVENT_TYPE_REQUEST_CANCEL_EXTERNAL_WORKFLOW_EXECUTION_FAILED: Temporal Server could not cancel the targeted Workflow\nThis is usually because the target Workflow could not be found\n - EVENT_TYPE_EXTERNAL_WORKFLOW_EXECUTION_CANCEL_REQUESTED: Temporal Server has successfully requested the cancellation of the target Workflow\n - EVENT_TYPE_MARKER_RECORDED: A marker has been recorded.\nThis event type is transparent to the Temporal Server\nThe Server will only store it and will not try to understand it.\n - EVENT_TYPE_WORKFLOW_EXECUTION_SIGNALED: Workflow has received a Signal event\nThe event type contains the Signal name, as well as a Signal payload\n - EVENT_TYPE_WORKFLOW_EXECUTION_TERMINATED: Workflow execution has been forcefully terminated\nThis is usually because the terminate Workflow API was called\n - EVENT_TYPE_WORKFLOW_EXECUTION_CONTINUED_AS_NEW: Workflow has successfully completed and a new Workflow has been started within the same transaction\nContains last Workflow execution results as well as new Workflow execution inputs\n - EVENT_TYPE_START_CHILD_WORKFLOW_EXECUTION_INITIATED: Temporal Server will try to start a child Workflow\n - EVENT_TYPE_START_CHILD_WORKFLOW_EXECUTION_FAILED: Child Workflow execution cannot be started/triggered\nUsually due to a child Workflow ID collision\n - EVENT_TYPE_CHILD_WORKFLOW_EXECUTION_STARTED: Child Workflow execution has successfully started/triggered\n - EVENT_TYPE_CHILD_WORKFLOW_EXECUTION_COMPLETED: Child Workflow execution has successfully completed\n - EVENT_TYPE_CHILD_WORKFLOW_EXECUTION_FAILED: Child Workflow execution has unsuccessfully completed\n - EVENT_TYPE_CHILD_WORKFLOW_EXECUTION_CANCELED: Child Workflow execution has been cancelled\n - EVENT_TYPE_CHILD_WORKFLOW_EXECUTION_TIMED_OUT: Child Workflow execution has timed out by the Temporal Server\n - EVENT_TYPE_CHILD_WORKFLOW_EXECUTION_TERMINATED: Child Workflow execution has been terminated\n - EVENT_TYPE_SIGNAL_EXTERNAL_WORKFLOW_EXECUTION_INITIATED: Temporal Server will try to Signal the targeted Workflow\nContains the Signal name, as well as a Signal payload\n - EVENT_TYPE_SIGNAL_EXTERNAL_WORKFLOW_EXECUTION_FAILED: Temporal Server cannot Signal the targeted Workflow\nUsually because the Workflow could not be found\n - EVENT_TYPE_EXTERNAL_WORKFLOW_EXECUTION_SIGNALED: Temporal Server has successfully Signaled the targeted Workflow\n - EVENT_TYPE_UPSERT_WORKFLOW_SEARCH_ATTRIBUTES: Workflow search attributes should be updated and synchronized with the visibility store\n - EVENT_TYPE_WORKFLOW_EXECUTION_UPDATE_ADMITTED: An update was admitted. Note that not all admitted updates result in this\nevent. See UpdateAdmittedEventOrigin for situations in which this event\nis created.\n - EVENT_TYPE_WORKFLOW_EXECUTION_UPDATE_ACCEPTED: An update was accepted (i.e. passed validation, perhaps because no validator was defined)\n - EVENT_TYPE_WORKFLOW_EXECUTION_UPDATE_REJECTED: This event is never written to history.\n - EVENT_TYPE_WORKFLOW_EXECUTION_UPDATE_COMPLETED: An update completed\n - EVENT_TYPE_WORKFLOW_PROPERTIES_MODIFIED_EXTERNALLY: Some property or properties of the workflow as a whole have changed by non-workflow code.\nThe distinction of external vs. command-based modification is important so the SDK can\nmaintain determinism when using the command-based approach.\n - EVENT_TYPE_ACTIVITY_PROPERTIES_MODIFIED_EXTERNALLY: Some property or properties of an already-scheduled activity have changed by non-workflow code.\nThe distinction of external vs. command-based modification is important so the SDK can\nmaintain determinism when using the command-based approach.\n - EVENT_TYPE_WORKFLOW_PROPERTIES_MODIFIED: Workflow properties modified by user workflow code\n - EVENT_TYPE_NEXUS_OPERATION_SCHEDULED: A Nexus operation was scheduled using a ScheduleNexusOperation command.\n - EVENT_TYPE_NEXUS_OPERATION_STARTED: An asynchronous Nexus operation was started by a Nexus handler.\n - EVENT_TYPE_NEXUS_OPERATION_COMPLETED: A Nexus operation completed successfully.\n - EVENT_TYPE_NEXUS_OPERATION_FAILED: A Nexus operation failed.\n - EVENT_TYPE_NEXUS_OPERATION_CANCELED: A Nexus operation completed as canceled.\n - EVENT_TYPE_NEXUS_OPERATION_TIMED_OUT: A Nexus operation timed out.\n - EVENT_TYPE_NEXUS_OPERATION_CANCEL_REQUESTED: A Nexus operation was requested to be canceled using a RequestCancelNexusOperation command.\n - EVENT_TYPE_WORKFLOW_EXECUTION_OPTIONS_UPDATED: Workflow execution options updated by user.\n - EVENT_TYPE_NEXUS_OPERATION_CANCEL_REQUEST_COMPLETED: A cancellation request for a Nexus operation was successfully delivered to the Nexus handler.\n - EVENT_TYPE_NEXUS_OPERATION_CANCEL_REQUEST_FAILED: A cancellation request for a Nexus operation resulted in an error.\n - EVENT_TYPE_WORKFLOW_EXECUTION_PAUSED: An event that indicates that the workflow execution has been paused.\n - EVENT_TYPE_WORKFLOW_EXECUTION_UNPAUSED: An event that indicates that the previously paused workflow execution has been unpaused.\n - EVENT_TYPE_WORKFLOW_EXECUTION_TIME_SKIPPING_TRANSITIONED: An event that indicates time skipping advanced time or was disabled automatically after a bound was reached.\n - EVENT_TYPE_WORKFLOW_STREAM_SUBSCRIBED: A Workflow subscribed to a stream. Recorded once per subscription, not\nper message: the offsets a task consumed ride WorkflowTaskCompleted and\nthe payloads never enter History at all.\n - EVENT_TYPE_WORKFLOW_STREAM_MESSAGES_ADDED: A Workflow published a batch of messages to a stream. Recorded per\nbatch, and carrying only the offset range it landed at: the bodies go to\nthe stream's own log, never into History.", + "description": "- EVENT_TYPE_UNSPECIFIED: Place holder and should never appear in a Workflow execution history\n - EVENT_TYPE_WORKFLOW_EXECUTION_STARTED: Workflow execution has been triggered/started\nIt contains Workflow execution inputs, as well as Workflow timeout configurations\n - EVENT_TYPE_WORKFLOW_EXECUTION_COMPLETED: Workflow execution has successfully completed and contains Workflow execution results\n - EVENT_TYPE_WORKFLOW_EXECUTION_FAILED: Workflow execution has unsuccessfully completed and contains the Workflow execution error\n - EVENT_TYPE_WORKFLOW_EXECUTION_TIMED_OUT: Workflow execution has timed out by the Temporal Server\nUsually due to the Workflow having not been completed within timeout settings\n - EVENT_TYPE_WORKFLOW_TASK_SCHEDULED: Workflow Task has been scheduled and the SDK client should now be able to process any new history events\n - EVENT_TYPE_WORKFLOW_TASK_STARTED: Workflow Task has started and the SDK client has picked up the Workflow Task and is processing new history events\n - EVENT_TYPE_WORKFLOW_TASK_COMPLETED: Workflow Task has completed\nThe SDK client picked up the Workflow Task and processed new history events\nSDK client may or may not ask the Temporal Server to do additional work, such as:\nEVENT_TYPE_ACTIVITY_TASK_SCHEDULED\nEVENT_TYPE_TIMER_STARTED\nEVENT_TYPE_UPSERT_WORKFLOW_SEARCH_ATTRIBUTES\nEVENT_TYPE_MARKER_RECORDED\nEVENT_TYPE_START_CHILD_WORKFLOW_EXECUTION_INITIATED\nEVENT_TYPE_REQUEST_CANCEL_EXTERNAL_WORKFLOW_EXECUTION_INITIATED\nEVENT_TYPE_SIGNAL_EXTERNAL_WORKFLOW_EXECUTION_INITIATED\nEVENT_TYPE_WORKFLOW_EXECUTION_COMPLETED\nEVENT_TYPE_WORKFLOW_EXECUTION_FAILED\nEVENT_TYPE_WORKFLOW_EXECUTION_CANCELED\nEVENT_TYPE_WORKFLOW_EXECUTION_CONTINUED_AS_NEW\n - EVENT_TYPE_WORKFLOW_TASK_TIMED_OUT: Workflow Task encountered a timeout\nEither an SDK client with a local cache was not available at the time, or it took too long for the SDK client to process the task\n - EVENT_TYPE_WORKFLOW_TASK_FAILED: Workflow Task encountered a failure\nUsually this means that the Workflow was non-deterministic\nHowever, the Workflow reset functionality also uses this event\n - EVENT_TYPE_ACTIVITY_TASK_SCHEDULED: Activity Task was scheduled\nThe SDK client should pick up this activity task and execute\nThis event type contains activity inputs, as well as activity timeout configurations\n - EVENT_TYPE_ACTIVITY_TASK_STARTED: Activity Task has started executing\nThe SDK client has picked up the Activity Task and is processing the Activity invocation\n - EVENT_TYPE_ACTIVITY_TASK_COMPLETED: Activity Task has finished successfully\nThe SDK client has picked up and successfully completed the Activity Task\nThis event type contains Activity execution results\n - EVENT_TYPE_ACTIVITY_TASK_FAILED: Activity Task has finished unsuccessfully\nThe SDK picked up the Activity Task but unsuccessfully completed it\nThis event type contains Activity execution errors\n - EVENT_TYPE_ACTIVITY_TASK_TIMED_OUT: Activity has timed out according to the Temporal Server\nActivity did not complete within the timeout settings\n - EVENT_TYPE_ACTIVITY_TASK_CANCEL_REQUESTED: A request to cancel the Activity has occurred\nThe SDK client will be able to confirm cancellation of an Activity during an Activity heartbeat\n - EVENT_TYPE_ACTIVITY_TASK_CANCELED: Activity has been cancelled\n - EVENT_TYPE_TIMER_STARTED: A timer has started\n - EVENT_TYPE_TIMER_FIRED: A timer has fired\n - EVENT_TYPE_TIMER_CANCELED: A time has been cancelled\n - EVENT_TYPE_WORKFLOW_EXECUTION_CANCEL_REQUESTED: A request has been made to cancel the Workflow execution\n - EVENT_TYPE_WORKFLOW_EXECUTION_CANCELED: SDK client has confirmed the cancellation request and the Workflow execution has been cancelled\n - EVENT_TYPE_REQUEST_CANCEL_EXTERNAL_WORKFLOW_EXECUTION_INITIATED: Workflow has requested that the Temporal Server try to cancel another Workflow\n - EVENT_TYPE_REQUEST_CANCEL_EXTERNAL_WORKFLOW_EXECUTION_FAILED: Temporal Server could not cancel the targeted Workflow\nThis is usually because the target Workflow could not be found\n - EVENT_TYPE_EXTERNAL_WORKFLOW_EXECUTION_CANCEL_REQUESTED: Temporal Server has successfully requested the cancellation of the target Workflow\n - EVENT_TYPE_MARKER_RECORDED: A marker has been recorded.\nThis event type is transparent to the Temporal Server\nThe Server will only store it and will not try to understand it.\n - EVENT_TYPE_WORKFLOW_EXECUTION_SIGNALED: Workflow has received a Signal event\nThe event type contains the Signal name, as well as a Signal payload\n - EVENT_TYPE_WORKFLOW_EXECUTION_TERMINATED: Workflow execution has been forcefully terminated\nThis is usually because the terminate Workflow API was called\n - EVENT_TYPE_WORKFLOW_EXECUTION_CONTINUED_AS_NEW: Workflow has successfully completed and a new Workflow has been started within the same transaction\nContains last Workflow execution results as well as new Workflow execution inputs\n - EVENT_TYPE_START_CHILD_WORKFLOW_EXECUTION_INITIATED: Temporal Server will try to start a child Workflow\n - EVENT_TYPE_START_CHILD_WORKFLOW_EXECUTION_FAILED: Child Workflow execution cannot be started/triggered\nUsually due to a child Workflow ID collision\n - EVENT_TYPE_CHILD_WORKFLOW_EXECUTION_STARTED: Child Workflow execution has successfully started/triggered\n - EVENT_TYPE_CHILD_WORKFLOW_EXECUTION_COMPLETED: Child Workflow execution has successfully completed\n - EVENT_TYPE_CHILD_WORKFLOW_EXECUTION_FAILED: Child Workflow execution has unsuccessfully completed\n - EVENT_TYPE_CHILD_WORKFLOW_EXECUTION_CANCELED: Child Workflow execution has been cancelled\n - EVENT_TYPE_CHILD_WORKFLOW_EXECUTION_TIMED_OUT: Child Workflow execution has timed out by the Temporal Server\n - EVENT_TYPE_CHILD_WORKFLOW_EXECUTION_TERMINATED: Child Workflow execution has been terminated\n - EVENT_TYPE_SIGNAL_EXTERNAL_WORKFLOW_EXECUTION_INITIATED: Temporal Server will try to Signal the targeted Workflow\nContains the Signal name, as well as a Signal payload\n - EVENT_TYPE_SIGNAL_EXTERNAL_WORKFLOW_EXECUTION_FAILED: Temporal Server cannot Signal the targeted Workflow\nUsually because the Workflow could not be found\n - EVENT_TYPE_EXTERNAL_WORKFLOW_EXECUTION_SIGNALED: Temporal Server has successfully Signaled the targeted Workflow\n - EVENT_TYPE_UPSERT_WORKFLOW_SEARCH_ATTRIBUTES: Workflow search attributes should be updated and synchronized with the visibility store\n - EVENT_TYPE_WORKFLOW_EXECUTION_UPDATE_ADMITTED: An update was admitted. Note that not all admitted updates result in this\nevent. See UpdateAdmittedEventOrigin for situations in which this event\nis created.\n - EVENT_TYPE_WORKFLOW_EXECUTION_UPDATE_ACCEPTED: An update was accepted (i.e. passed validation, perhaps because no validator was defined)\n - EVENT_TYPE_WORKFLOW_EXECUTION_UPDATE_REJECTED: This event is never written to history.\n - EVENT_TYPE_WORKFLOW_EXECUTION_UPDATE_COMPLETED: An update completed\n - EVENT_TYPE_WORKFLOW_PROPERTIES_MODIFIED_EXTERNALLY: Some property or properties of the workflow as a whole have changed by non-workflow code.\nThe distinction of external vs. command-based modification is important so the SDK can\nmaintain determinism when using the command-based approach.\n - EVENT_TYPE_ACTIVITY_PROPERTIES_MODIFIED_EXTERNALLY: Some property or properties of an already-scheduled activity have changed by non-workflow code.\nThe distinction of external vs. command-based modification is important so the SDK can\nmaintain determinism when using the command-based approach.\n - EVENT_TYPE_WORKFLOW_PROPERTIES_MODIFIED: Workflow properties modified by user workflow code\n - EVENT_TYPE_NEXUS_OPERATION_SCHEDULED: A Nexus operation was scheduled using a ScheduleNexusOperation command.\n - EVENT_TYPE_NEXUS_OPERATION_STARTED: An asynchronous Nexus operation was started by a Nexus handler.\n - EVENT_TYPE_NEXUS_OPERATION_COMPLETED: A Nexus operation completed successfully.\n - EVENT_TYPE_NEXUS_OPERATION_FAILED: A Nexus operation failed.\n - EVENT_TYPE_NEXUS_OPERATION_CANCELED: A Nexus operation completed as canceled.\n - EVENT_TYPE_NEXUS_OPERATION_TIMED_OUT: A Nexus operation timed out.\n - EVENT_TYPE_NEXUS_OPERATION_CANCEL_REQUESTED: A Nexus operation was requested to be canceled using a RequestCancelNexusOperation command.\n - EVENT_TYPE_WORKFLOW_EXECUTION_OPTIONS_UPDATED: Workflow execution options updated by user.\n - EVENT_TYPE_NEXUS_OPERATION_CANCEL_REQUEST_COMPLETED: A cancellation request for a Nexus operation was successfully delivered to the Nexus handler.\n - EVENT_TYPE_NEXUS_OPERATION_CANCEL_REQUEST_FAILED: A cancellation request for a Nexus operation resulted in an error.\n - EVENT_TYPE_WORKFLOW_EXECUTION_PAUSED: An event that indicates that the workflow execution has been paused.\n - EVENT_TYPE_WORKFLOW_EXECUTION_UNPAUSED: An event that indicates that the previously paused workflow execution has been unpaused.\n - EVENT_TYPE_WORKFLOW_EXECUTION_TIME_SKIPPING_TRANSITIONED: An event that indicates time skipping advanced time or was disabled automatically after a bound was reached.\n - EVENT_TYPE_WORKFLOW_STREAM_SUBSCRIBED: A Workflow subscribed to a stream. Recorded once per subscription, not\nper record: the offsets a task consumed ride WorkflowTaskCompleted and\nthe payloads never enter History at all.\n - EVENT_TYPE_WORKFLOW_STREAM_RECORDS_APPENDED: A Workflow appended a batch of records to a stream. Recorded per\nbatch, and carrying only the offset range it landed at: the bodies go to\nthe stream's own log, never into History.", "title": "Whenever this list of events is changed do change the function shouldBufferEvent in mutableStateBuilder.go to make sure to do the correct event ordering" }, "v1Execution": { @@ -16792,8 +16792,8 @@ "workflowStreamSubscribedEventAttributes": { "$ref": "#/definitions/v1WorkflowStreamSubscribedEventAttributes" }, - "workflowStreamMessagesAddedEventAttributes": { - "$ref": "#/definitions/v1WorkflowStreamMessagesAddedEventAttributes" + "workflowStreamRecordsAppendedEventAttributes": { + "$ref": "#/definitions/v1WorkflowStreamRecordsAppendedEventAttributes" } }, "description": "History events are the method by which Temporal SDKs advance (or recreate) workflow state.\nSee the `EventType` enum for more info about what each event is for." @@ -20065,7 +20065,7 @@ } } }, - "v1StreamCursor": { + "v1StreamRange": { "type": "object", "properties": { "streamId": { @@ -20073,21 +20073,23 @@ }, "fromOffset": { "type": "string", - "format": "int64" + "format": "int64", + "description": "Inclusive." }, "toOffset": { "type": "string", - "format": "int64" + "format": "int64", + "description": "Exclusive." } }, - "description": "The offsets a Workflow Task consumed, without the payloads. Recorded on\nWorkflowTaskCompleted so History grows with Workflow Tasks rather than with\nmessages." + "description": "The offsets a Workflow Task consumed, without the payloads. Recorded on\nWorkflowTaskCompleted so History grows with Workflow Tasks rather than with\nrecords." }, - "v1StreamMessage": { + "v1StreamRecord": { "type": "object", "properties": { "body": { "$ref": "#/definitions/v1Payload", - "description": "The message itself, stored as sent." + "description": "The value the producer published, stored as sent. A payload codec\napplies here as it does to any other payload." }, "metadata": { "type": "object", @@ -20100,12 +20102,36 @@ "type": "string", "description": "Producer-supplied grouping label, stored as sent." }, - "topicSequence": { + "kind": { + "$ref": "#/definitions/v1StreamRecordKind", + "description": "How to read this record. Unspecified is read as DATA." + }, + "producerId": { + "type": "string", + "description": "Who wrote the record. Empty when the owning Workflow did." + }, + "attempt": { + "type": "string", + "format": "int64", + "description": "The producer's attempt. Readers treat a later attempt by the same\nproducer as superseding what the earlier one wrote." + }, + "sequence": { "type": "string", "format": "int64", - "description": "Producer-supplied position within `topic`. The server stores it as sent\nand does not assign, validate or order by it." + "description": "The producer's position within its attempt, or -1 when unnumbered.\nStored as sent; the server does not assign, validate or order by it." } - } + }, + "description": "One entry in a stream. The record is the wire format: stores keep it\nserialized as is and readers in every language decode the same bytes." + }, + "v1StreamRecordKind": { + "type": "string", + "enum": [ + "STREAM_RECORD_KIND_UNSPECIFIED", + "STREAM_RECORD_KIND_DATA", + "STREAM_RECORD_KIND_FINISH" + ], + "default": "STREAM_RECORD_KIND_UNSPECIFIED", + "description": "What a record means to a reader. Kept on the record itself so every store\nand every language reads it the same way without a private envelope.\n\n - STREAM_RECORD_KIND_UNSPECIFIED: Read as DATA.\n - STREAM_RECORD_KIND_DATA: A value the producer published; `body` carries it.\n - STREAM_RECORD_KIND_FINISH: The producer named by `producer_id` writes nothing more on `topic`.\nSays nothing about that producer's outcome and does not end the stream." }, "v1StreamSlice": { "type": "object", @@ -20127,20 +20153,20 @@ "format": "int64", "description": "Exclusive. Equal to from_offset when the subscription observed nothing,\nwhich is a fact replay has to reproduce rather than an absence of one." }, - "messages": { + "records": { "type": "array", "items": { "type": "object", - "$ref": "#/definitions/v1StreamMessage" + "$ref": "#/definitions/v1StreamRecord" } }, "workflowTaskCompletedEventId": { "type": "string", "format": "int64", - "description": "The WorkflowTaskCompleted event whose stream_cursors recorded this range.\nSet only when the server is re-supplying a range for a task being\nreplayed; a slice for the task now being started leaves it unset, because\nthe event closing that task does not exist yet.\n\nReplay needs this because a Workflow Task response carries one slice set\nwhile a cache miss replays every prior task, so the ranges have to be\nmatched to the events that recorded them rather than to the response." + "description": "The WorkflowTaskCompleted event whose consumed_stream_ranges recorded\nthis range. Set only when the server is re-supplying a range for a task\nbeing replayed; a slice for the task now being started leaves it unset,\nbecause the event closing that task does not exist yet.\n\nReplay needs this because a Workflow Task response carries one slice set\nwhile a cache miss replays every prior task, so the ranges have to be\nmatched to the events that recorded them rather than to the response." } }, - "description": "A contiguous range of a stream delivered to a Workflow Task, along with the\noffsets it covers. The offsets are what History records; the messages\nthemselves are never written to History." + "description": "A contiguous range of a stream delivered to a Workflow Task, along with the\noffsets it covers. The offsets are what History records; the records\nthemselves are never written to History." }, "v1StructuredCalendarSpec": { "type": "object", @@ -22518,27 +22544,27 @@ } } }, - "v1WorkflowStreamMessagesAddedEventAttributes": { + "v1WorkflowStreamRecordsAppendedEventAttributes": { "type": "object", "properties": { "workflowTaskCompletedEventId": { "type": "string", "format": "int64", - "description": "The WorkflowTaskCompleted event of the task whose command published this\nbatch." + "description": "The WorkflowTaskCompleted event of the task whose command appended this\nbatch." }, "streamId": { "type": "string", - "description": "Stream the Workflow published to." + "description": "Stream the Workflow appended to." }, "firstOffset": { "type": "string", "format": "int64", - "description": "Offset the first message of the batch landed at." + "description": "Offset the first record of the batch landed at." }, - "messageCount": { + "recordCount": { "type": "string", "format": "int64", - "description": "How many messages the batch held. With first_offset this names the range\nwithout carrying any of it, which is what keeps this event a fixed size\nno matter how large the batch or its payloads are." + "description": "How many records the batch held. With first_offset this names the range\nwithout carrying any of it, which is what keeps this event a fixed size\nno matter how large the batch or its payloads are." } } }, @@ -22614,13 +22640,13 @@ "$ref": "#/definitions/v1WorkerDeploymentVersion", "description": "The Worker Deployment Version that completed this task. Must be set if `versioning_behavior`\nis set. This value updates workflow execution's `versioning_info.deployment_version`." }, - "streamCursors": { + "consumedStreamRanges": { "type": "array", "items": { "type": "object", - "$ref": "#/definitions/v1StreamCursor" + "$ref": "#/definitions/v1StreamRange" }, - "description": "Offset ranges this Workflow Task consumed from streams it subscribes to.\nRecorded on every task where a subscription is active, including when it\nobserved nothing: an empty range is a fact replay must reproduce, and\nomitting it would let replay deliver messages the Workflow did not have.\nNumbered 20 to leave 14 through 19 free for fields added on the main line." + "description": "Offset ranges this Workflow Task consumed from streams it subscribes to.\nRecorded on every task where a subscription is active, including when it\nobserved nothing: an empty range is a fact replay must reproduce, and\nomitting it would let replay deliver records the Workflow did not have.\nNumbered 20 to leave 14 through 19 free for fields added on the main line." } } }, @@ -22698,12 +22724,12 @@ "WORKFLOW_TASK_FAILED_CAUSE_EXTERNAL_STORAGE_FAILURE", "WORKFLOW_TASK_FAILED_CAUSE_WORKFLOW_PAUSE_REQUESTED_BEFORE_TASK_STARTED", "WORKFLOW_TASK_FAILED_CAUSE_REQUEST_TOO_LARGE", - "WORKFLOW_TASK_FAILED_CAUSE_BAD_ADD_STREAM_MESSAGES_ATTRIBUTES", + "WORKFLOW_TASK_FAILED_CAUSE_BAD_APPEND_STREAM_RECORDS_ATTRIBUTES", "WORKFLOW_TASK_FAILED_CAUSE_BAD_SUBSCRIBE_STREAM_ATTRIBUTES", "WORKFLOW_TASK_FAILED_CAUSE_STREAM_RANGE_UNAVAILABLE" ], "default": "WORKFLOW_TASK_FAILED_CAUSE_UNSPECIFIED", - "description": "Workflow tasks can fail for various reasons. Note that some of these reasons can only originate\nfrom the server, and some of them can only originate from the SDK/worker.\n\n - WORKFLOW_TASK_FAILED_CAUSE_UNHANDLED_COMMAND: Between starting and completing the workflow task (with a workflow completion command), some\nnew command (like a signal) was processed into workflow history. The outstanding task will be\nfailed with this reason, and a worker must pick up a new task.\n - WORKFLOW_TASK_FAILED_CAUSE_RESET_STICKY_TASK_QUEUE: The worker wishes to fail the task and have the next one be generated on a normal, not sticky\nqueue. Generally workers should prefer to use the explicit `ResetStickyTaskQueue` RPC call.\n - WORKFLOW_TASK_FAILED_CAUSE_NON_DETERMINISTIC_ERROR: The worker encountered a mismatch while replaying history between what was expected, and\nwhat the workflow code actually did.\n - WORKFLOW_TASK_FAILED_CAUSE_PENDING_CHILD_WORKFLOWS_LIMIT_EXCEEDED: We send the below error codes to users when their requests would violate a size constraint\nof their workflow. We do this to ensure that the state of their workflow does not become too\nlarge because that can cause severe performance degradation. You can modify the thresholds for\neach of these errors within your dynamic config.\n\nSpawning a new child workflow would cause this workflow to exceed its limit of pending child\nworkflows.\n - WORKFLOW_TASK_FAILED_CAUSE_PENDING_ACTIVITIES_LIMIT_EXCEEDED: Starting a new activity would cause this workflow to exceed its limit of pending activities\nthat we track.\n - WORKFLOW_TASK_FAILED_CAUSE_PENDING_SIGNALS_LIMIT_EXCEEDED: A workflow has a buffer of signals that have not yet reached their destination. We return this\nerror when sending a new signal would exceed the capacity of this buffer.\n - WORKFLOW_TASK_FAILED_CAUSE_PENDING_REQUEST_CANCEL_LIMIT_EXCEEDED: Similarly, we have a buffer of pending requests to cancel other workflows. We return this error\nwhen our capacity for pending cancel requests is already reached.\n - WORKFLOW_TASK_FAILED_CAUSE_BAD_UPDATE_WORKFLOW_EXECUTION_MESSAGE: Workflow execution update message (update.Acceptance, update.Rejection, or update.Response)\nhas wrong format, or missing required fields.\n - WORKFLOW_TASK_FAILED_CAUSE_UNHANDLED_UPDATE: Similar to WORKFLOW_TASK_FAILED_CAUSE_UNHANDLED_COMMAND, but for updates.\n - WORKFLOW_TASK_FAILED_CAUSE_BAD_SCHEDULE_NEXUS_OPERATION_ATTRIBUTES: A workflow task completed with an invalid ScheduleNexusOperation command.\n - WORKFLOW_TASK_FAILED_CAUSE_PENDING_NEXUS_OPERATIONS_LIMIT_EXCEEDED: A workflow task completed requesting to schedule a Nexus Operation exceeding the server configured limit.\n - WORKFLOW_TASK_FAILED_CAUSE_BAD_REQUEST_CANCEL_NEXUS_OPERATION_ATTRIBUTES: A workflow task completed with an invalid RequestCancelNexusOperation command.\n - WORKFLOW_TASK_FAILED_CAUSE_FEATURE_DISABLED: A workflow task completed requesting a feature that's disabled on the server (either system wide or - typically -\nfor the workflow's namespace).\nCheck the workflow task failure message for more information.\n - WORKFLOW_TASK_FAILED_CAUSE_GRPC_MESSAGE_TOO_LARGE: A workflow task failed because a grpc message was too large.\n - WORKFLOW_TASK_FAILED_CAUSE_PAYLOADS_TOO_LARGE: A workflow task failed because payloads were too large.\n - WORKFLOW_TASK_FAILED_CAUSE_EXTERNAL_STORAGE_FAILURE: A workflow task failed because an external storage operation failed.\nCheck the workflow task failure message for more information.\n - WORKFLOW_TASK_FAILED_CAUSE_WORKFLOW_PAUSE_REQUESTED_BEFORE_TASK_STARTED: A workflow task is failed because the workflow is paused before the task is started.\n - WORKFLOW_TASK_FAILED_CAUSE_REQUEST_TOO_LARGE: A workflow task failed because the request exceeded a size limit.\n - WORKFLOW_TASK_FAILED_CAUSE_BAD_ADD_STREAM_MESSAGES_ATTRIBUTES: A workflow task completed with an invalid AddStreamMessages command.\n - WORKFLOW_TASK_FAILED_CAUSE_BAD_SUBSCRIBE_STREAM_ATTRIBUTES: A workflow task completed with an invalid SubscribeStream command.\n - WORKFLOW_TASK_FAILED_CAUSE_STREAM_RANGE_UNAVAILABLE: A workflow task could not be started because a stream range it consumed and recorded in\nHistory can no longer be served, for example after truncation or because it exceeds the\nreplay bound. Check the workflow task failure message for more information." + "description": "Workflow tasks can fail for various reasons. Note that some of these reasons can only originate\nfrom the server, and some of them can only originate from the SDK/worker.\n\n - WORKFLOW_TASK_FAILED_CAUSE_UNHANDLED_COMMAND: Between starting and completing the workflow task (with a workflow completion command), some\nnew command (like a signal) was processed into workflow history. The outstanding task will be\nfailed with this reason, and a worker must pick up a new task.\n - WORKFLOW_TASK_FAILED_CAUSE_RESET_STICKY_TASK_QUEUE: The worker wishes to fail the task and have the next one be generated on a normal, not sticky\nqueue. Generally workers should prefer to use the explicit `ResetStickyTaskQueue` RPC call.\n - WORKFLOW_TASK_FAILED_CAUSE_NON_DETERMINISTIC_ERROR: The worker encountered a mismatch while replaying history between what was expected, and\nwhat the workflow code actually did.\n - WORKFLOW_TASK_FAILED_CAUSE_PENDING_CHILD_WORKFLOWS_LIMIT_EXCEEDED: We send the below error codes to users when their requests would violate a size constraint\nof their workflow. We do this to ensure that the state of their workflow does not become too\nlarge because that can cause severe performance degradation. You can modify the thresholds for\neach of these errors within your dynamic config.\n\nSpawning a new child workflow would cause this workflow to exceed its limit of pending child\nworkflows.\n - WORKFLOW_TASK_FAILED_CAUSE_PENDING_ACTIVITIES_LIMIT_EXCEEDED: Starting a new activity would cause this workflow to exceed its limit of pending activities\nthat we track.\n - WORKFLOW_TASK_FAILED_CAUSE_PENDING_SIGNALS_LIMIT_EXCEEDED: A workflow has a buffer of signals that have not yet reached their destination. We return this\nerror when sending a new signal would exceed the capacity of this buffer.\n - WORKFLOW_TASK_FAILED_CAUSE_PENDING_REQUEST_CANCEL_LIMIT_EXCEEDED: Similarly, we have a buffer of pending requests to cancel other workflows. We return this error\nwhen our capacity for pending cancel requests is already reached.\n - WORKFLOW_TASK_FAILED_CAUSE_BAD_UPDATE_WORKFLOW_EXECUTION_MESSAGE: Workflow execution update message (update.Acceptance, update.Rejection, or update.Response)\nhas wrong format, or missing required fields.\n - WORKFLOW_TASK_FAILED_CAUSE_UNHANDLED_UPDATE: Similar to WORKFLOW_TASK_FAILED_CAUSE_UNHANDLED_COMMAND, but for updates.\n - WORKFLOW_TASK_FAILED_CAUSE_BAD_SCHEDULE_NEXUS_OPERATION_ATTRIBUTES: A workflow task completed with an invalid ScheduleNexusOperation command.\n - WORKFLOW_TASK_FAILED_CAUSE_PENDING_NEXUS_OPERATIONS_LIMIT_EXCEEDED: A workflow task completed requesting to schedule a Nexus Operation exceeding the server configured limit.\n - WORKFLOW_TASK_FAILED_CAUSE_BAD_REQUEST_CANCEL_NEXUS_OPERATION_ATTRIBUTES: A workflow task completed with an invalid RequestCancelNexusOperation command.\n - WORKFLOW_TASK_FAILED_CAUSE_FEATURE_DISABLED: A workflow task completed requesting a feature that's disabled on the server (either system wide or - typically -\nfor the workflow's namespace).\nCheck the workflow task failure message for more information.\n - WORKFLOW_TASK_FAILED_CAUSE_GRPC_MESSAGE_TOO_LARGE: A workflow task failed because a grpc message was too large.\n - WORKFLOW_TASK_FAILED_CAUSE_PAYLOADS_TOO_LARGE: A workflow task failed because payloads were too large.\n - WORKFLOW_TASK_FAILED_CAUSE_EXTERNAL_STORAGE_FAILURE: A workflow task failed because an external storage operation failed.\nCheck the workflow task failure message for more information.\n - WORKFLOW_TASK_FAILED_CAUSE_WORKFLOW_PAUSE_REQUESTED_BEFORE_TASK_STARTED: A workflow task is failed because the workflow is paused before the task is started.\n - WORKFLOW_TASK_FAILED_CAUSE_REQUEST_TOO_LARGE: A workflow task failed because the request exceeded a size limit.\n - WORKFLOW_TASK_FAILED_CAUSE_BAD_APPEND_STREAM_RECORDS_ATTRIBUTES: A workflow task completed with an invalid AppendStreamRecords command.\n - WORKFLOW_TASK_FAILED_CAUSE_BAD_SUBSCRIBE_STREAM_ATTRIBUTES: A workflow task completed with an invalid SubscribeStream command.\n - WORKFLOW_TASK_FAILED_CAUSE_STREAM_RANGE_UNAVAILABLE: A workflow task could not be started because a stream range it consumed and recorded in\nHistory can no longer be served, for example after truncation or because it exceeds the\nreplay bound. Check the workflow task failure message for more information." }, "v1WorkflowTaskFailedEventAttributes": { "type": "object", diff --git a/openapi/openapiv3.yaml b/openapi/openapiv3.yaml index 92c4b24f1..5c4fdd8bc 100644 --- a/openapi/openapiv3.yaml +++ b/openapi/openapiv3.yaml @@ -12879,7 +12879,7 @@ components: - EVENT_TYPE_WORKFLOW_EXECUTION_UNPAUSED - EVENT_TYPE_WORKFLOW_EXECUTION_TIME_SKIPPING_TRANSITIONED - EVENT_TYPE_WORKFLOW_STREAM_SUBSCRIBED - - EVENT_TYPE_WORKFLOW_STREAM_MESSAGES_ADDED + - EVENT_TYPE_WORKFLOW_STREAM_RECORDS_APPENDED type: string format: enum version: @@ -13047,8 +13047,8 @@ components: $ref: '#/components/schemas/WorkflowExecutionTimeSkippingTransitionedEventAttributes' workflowStreamSubscribedEventAttributes: $ref: '#/components/schemas/WorkflowStreamSubscribedEventAttributes' - workflowStreamMessagesAddedEventAttributes: - $ref: '#/components/schemas/WorkflowStreamMessagesAddedEventAttributes' + workflowStreamRecordsAppendedEventAttributes: + $ref: '#/components/schemas/WorkflowStreamRecordsAppendedEventAttributes' description: |- History events are the method by which Temporal SDKs advance (or recreate) workflow state. See the `EventType` enum for more info about what each event is for. @@ -15543,7 +15543,7 @@ components: - EVENT_TYPE_WORKFLOW_EXECUTION_UNPAUSED - EVENT_TYPE_WORKFLOW_EXECUTION_TIME_SKIPPING_TRANSITIONED - EVENT_TYPE_WORKFLOW_STREAM_SUBSCRIBED - - EVENT_TYPE_WORKFLOW_STREAM_MESSAGES_ADDED + - EVENT_TYPE_WORKFLOW_STREAM_RECORDS_APPENDED type: string description: The event type of the history event generated by the request. format: enum @@ -17695,26 +17695,30 @@ components: type: type: string description: The type of the driver, required. - StreamCursor: + StreamRange: type: object properties: streamId: type: string fromOffset: type: string + description: Inclusive. toOffset: type: string + description: Exclusive. description: |- The offsets a Workflow Task consumed, without the payloads. Recorded on WorkflowTaskCompleted so History grows with Workflow Tasks rather than with - messages. - StreamMessage: + records. + StreamRecord: type: object properties: body: allOf: - $ref: '#/components/schemas/Payload' - description: The message itself, stored as sent. + description: |- + The value the producer published, stored as sent. A payload codec + applies here as it does to any other payload. metadata: type: object additionalProperties: @@ -17723,11 +17727,30 @@ components: topic: type: string description: Producer-supplied grouping label, stored as sent. - topicSequence: + kind: + enum: + - STREAM_RECORD_KIND_UNSPECIFIED + - STREAM_RECORD_KIND_DATA + - STREAM_RECORD_KIND_FINISH + type: string + description: How to read this record. Unspecified is read as DATA. + format: enum + producerId: + type: string + description: Who wrote the record. Empty when the owning Workflow did. + attempt: + type: string + description: |- + The producer's attempt. Readers treat a later attempt by the same + producer as superseding what the earlier one wrote. + sequence: type: string description: |- - Producer-supplied position within `topic`. The server stores it as sent - and does not assign, validate or order by it. + The producer's position within its attempt, or -1 when unnumbered. + Stored as sent; the server does not assign, validate or order by it. + description: |- + One entry in a stream. The record is the wire format: stores keep it + serialized as is and readers in every language decode the same bytes. StreamSlice: type: object properties: @@ -17746,24 +17769,24 @@ components: description: |- Exclusive. Equal to from_offset when the subscription observed nothing, which is a fact replay has to reproduce rather than an absence of one. - messages: + records: type: array items: - $ref: '#/components/schemas/StreamMessage' + $ref: '#/components/schemas/StreamRecord' workflowTaskCompletedEventId: type: string description: |- - The WorkflowTaskCompleted event whose stream_cursors recorded this range. - Set only when the server is re-supplying a range for a task being - replayed; a slice for the task now being started leaves it unset, because - the event closing that task does not exist yet. + The WorkflowTaskCompleted event whose consumed_stream_ranges recorded + this range. Set only when the server is re-supplying a range for a task + being replayed; a slice for the task now being started leaves it unset, + because the event closing that task does not exist yet. Replay needs this because a Workflow Task response carries one slice set while a cache miss replays every prior task, so the ranges have to be matched to the events that recorded them rather than to the response. description: |- A contiguous range of a stream delivered to a Workflow Task, along with the - offsets it covers. The offsets are what History records; the messages + offsets it covers. The offsets are what History records; the records themselves are never written to History. StructuredCalendarSpec: type: object @@ -19916,7 +19939,7 @@ components: - EVENT_TYPE_WORKFLOW_EXECUTION_UNPAUSED - EVENT_TYPE_WORKFLOW_EXECUTION_TIME_SKIPPING_TRANSITIONED - EVENT_TYPE_WORKFLOW_STREAM_SUBSCRIBED - - EVENT_TYPE_WORKFLOW_STREAM_MESSAGES_ADDED + - EVENT_TYPE_WORKFLOW_STREAM_RECORDS_APPENDED type: string format: enum description: EventReference is a direct reference to a history event through the event ID. @@ -19989,7 +20012,7 @@ components: - EVENT_TYPE_WORKFLOW_EXECUTION_UNPAUSED - EVENT_TYPE_WORKFLOW_EXECUTION_TIME_SKIPPING_TRANSITIONED - EVENT_TYPE_WORKFLOW_STREAM_SUBSCRIBED - - EVENT_TYPE_WORKFLOW_STREAM_MESSAGES_ADDED + - EVENT_TYPE_WORKFLOW_STREAM_RECORDS_APPENDED type: string format: enum description: RequestIdReference is a indirect reference to a history event through the request ID. @@ -21112,24 +21135,24 @@ components: * BETWEEN ... AND STARTS_WITH description: Activity trigger will be triggered when an activity is about to start. - WorkflowStreamMessagesAddedEventAttributes: + WorkflowStreamRecordsAppendedEventAttributes: type: object properties: workflowTaskCompletedEventId: type: string description: |- - The WorkflowTaskCompleted event of the task whose command published this + The WorkflowTaskCompleted event of the task whose command appended this batch. streamId: type: string - description: Stream the Workflow published to. + description: Stream the Workflow appended to. firstOffset: type: string - description: Offset the first message of the batch landed at. - messageCount: + description: Offset the first record of the batch landed at. + recordCount: type: string description: |- - How many messages the batch held. With first_offset this names the range + How many records the batch held. With first_offset this names the range without carrying any of it, which is what keeps this event a fixed size no matter how large the batch or its payloads are. WorkflowStreamSubscribedEventAttributes: @@ -21221,15 +21244,15 @@ components: description: |- The Worker Deployment Version that completed this task. Must be set if `versioning_behavior` is set. This value updates workflow execution's `versioning_info.deployment_version`. - streamCursors: + consumedStreamRanges: type: array items: - $ref: '#/components/schemas/StreamCursor' + $ref: '#/components/schemas/StreamRange' description: |- Offset ranges this Workflow Task consumed from streams it subscribes to. Recorded on every task where a subscription is active, including when it observed nothing: an empty range is a fact replay must reproduce, and - omitting it would let replay deliver messages the Workflow did not have. + omitting it would let replay deliver records the Workflow did not have. Numbered 20 to leave 14 through 19 free for fields added on the main line. WorkflowTaskCompletedMetadata: type: object @@ -21338,7 +21361,7 @@ components: - WORKFLOW_TASK_FAILED_CAUSE_EXTERNAL_STORAGE_FAILURE - WORKFLOW_TASK_FAILED_CAUSE_WORKFLOW_PAUSE_REQUESTED_BEFORE_TASK_STARTED - WORKFLOW_TASK_FAILED_CAUSE_REQUEST_TOO_LARGE - - WORKFLOW_TASK_FAILED_CAUSE_BAD_ADD_STREAM_MESSAGES_ATTRIBUTES + - WORKFLOW_TASK_FAILED_CAUSE_BAD_APPEND_STREAM_RECORDS_ATTRIBUTES - WORKFLOW_TASK_FAILED_CAUSE_BAD_SUBSCRIBE_STREAM_ATTRIBUTES - WORKFLOW_TASK_FAILED_CAUSE_STREAM_RANGE_UNAVAILABLE type: string