diff --git a/changelog/added/headier-mackenzie.md b/changelog/added/headier-mackenzie.md new file mode 100644 index 000000000..66ea4d325 --- /dev/null +++ b/changelog/added/headier-mackenzie.md @@ -0,0 +1,2 @@ +Core: A local activity's `ActivityTask.Start` has `workflow_task` (field 21), with the started event id, attempt and start time of the workflow task in which Core dispatched it. `workflow_task` also has `previous_started_event_id`, `previous_attempt` and `previous_started_time`, which name the run's last completed workflow task, and `failed_tasks`, the started event ids of the run's last 100 failed or timed out workflow tasks. Retries that Core runs locally keep the value. Core leaves it unset for other activities. +Core: Client environment config profiles include the raw TOML tables under `profile..ext`, keyed by extension name, for SDK envconfig extensions. Strict mode accepts any content under `ext`. The C bridge's profile JSON includes them as an `ext` object, with TOML datetimes as strings. diff --git a/changelog/fixed/headier-mackenzie.md b/changelog/fixed/headier-mackenzie.md new file mode 100644 index 000000000..2c099ac2d --- /dev/null +++ b/changelog/fixed/headier-mackenzie.md @@ -0,0 +1,3 @@ +Core: A workflow task failure reported with the cause `WORKFLOW_TASK_FAILED_CAUSE_EXTERNAL_STORAGE_FAILURE` is now counted on `workflow_task_execution_failed` with `failure_reason="ExternalStorageError"`, matching activity failures with the storage cause. It was previously counted as `WorkflowError`. +Core: Ephemeral dev and test servers now complete the automatic port reservation handshake on Linux and macOS before starting, preventing intermittent address-in-use errors during TCP teardown. +Core: Resource-based worker tuners now read CPU usage and quotas from standard cgroup v1 mounts. Workers on cgroup v1 systems no longer fall back to host CPU usage and admit work based on understated container load. diff --git a/temporalio/bridge/Cargo.lock b/temporalio/bridge/Cargo.lock index deae7c52f..531d3a651 100644 --- a/temporalio/bridge/Cargo.lock +++ b/temporalio/bridge/Cargo.lock @@ -1222,9 +1222,9 @@ checksum = "f9f8bd3e56ce4dfc153cf470fffbfa98c7620958b312ca5c3a4b8d5181fd13c6" [[package]] name = "lru" -version = "0.18.5" +version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef9ac18847474e638e3702b76c65d4eb93428471a74778ef0f1be711717f89b5" +checksum = "4a9f71e3591c7ec44d3e563e87bf14ddc2bada8519dca046e5b0e560cd004e2d" dependencies = [ "hashbrown 0.17.1", ] diff --git a/temporalio/bridge/proto/activity_task/__init__.py b/temporalio/bridge/proto/activity_task/__init__.py index 779ebf353..9e69a0f89 100644 --- a/temporalio/bridge/proto/activity_task/__init__.py +++ b/temporalio/bridge/proto/activity_task/__init__.py @@ -4,6 +4,7 @@ ActivityTask, Cancel, Start, + WorkflowTaskAttempt, ) __all__ = [ @@ -12,4 +13,5 @@ "ActivityTask", "Cancel", "Start", + "WorkflowTaskAttempt", ] diff --git a/temporalio/bridge/proto/activity_task/activity_task_pb2.py b/temporalio/bridge/proto/activity_task/activity_task_pb2.py index 38bd426a7..cc7365b5d 100644 --- a/temporalio/bridge/proto/activity_task/activity_task_pb2.py +++ b/temporalio/bridge/proto/activity_task/activity_task_pb2.py @@ -29,7 +29,7 @@ ) DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile( - b'\n3temporal/sdk/core/activity_task/activity_task.proto\x12\x15\x63oresdk.activity_task\x1a\x1egoogle/protobuf/duration.proto\x1a\x1fgoogle/protobuf/timestamp.proto\x1a$temporal/api/common/v1/message.proto\x1a#temporal/api/nexus/v1/message.proto\x1a%temporal/sdk/core/common/common.proto"\x8d\x01\n\x0c\x41\x63tivityTask\x12\x12\n\ntask_token\x18\x01 \x01(\x0c\x12-\n\x05start\x18\x03 \x01(\x0b\x32\x1c.coresdk.activity_task.StartH\x00\x12/\n\x06\x63\x61ncel\x18\x04 \x01(\x0b\x32\x1d.coresdk.activity_task.CancelH\x00\x42\t\n\x07variant"\x98\x08\n\x05Start\x12\x1a\n\x12workflow_namespace\x18\x01 \x01(\t\x12\x15\n\rworkflow_type\x18\x02 \x01(\t\x12\x45\n\x12workflow_execution\x18\x03 \x01(\x0b\x32).temporal.api.common.v1.WorkflowExecution\x12\x13\n\x0b\x61\x63tivity_id\x18\x04 \x01(\t\x12\x15\n\ractivity_type\x18\x05 \x01(\t\x12\x45\n\rheader_fields\x18\x06 \x03(\x0b\x32..coresdk.activity_task.Start.HeaderFieldsEntry\x12.\n\x05input\x18\x07 \x03(\x0b\x32\x1f.temporal.api.common.v1.Payload\x12:\n\x11heartbeat_details\x18\x08 \x03(\x0b\x32\x1f.temporal.api.common.v1.Payload\x12\x32\n\x0escheduled_time\x18\t \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x42\n\x1e\x63urrent_attempt_scheduled_time\x18\n \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x30\n\x0cstarted_time\x18\x0b \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x0f\n\x07\x61ttempt\x18\x0c \x01(\r\x12<\n\x19schedule_to_close_timeout\x18\r \x01(\x0b\x32\x19.google.protobuf.Duration\x12\x39\n\x16start_to_close_timeout\x18\x0e \x01(\x0b\x32\x19.google.protobuf.Duration\x12\x34\n\x11heartbeat_timeout\x18\x0f \x01(\x0b\x32\x19.google.protobuf.Duration\x12\x39\n\x0cretry_policy\x18\x10 \x01(\x0b\x32#.temporal.api.common.v1.RetryPolicy\x12\x32\n\x08priority\x18\x12 \x01(\x0b\x32 .temporal.api.common.v1.Priority\x12\x10\n\x08is_local\x18\x11 \x01(\x08\x12\x0e\n\x06run_id\x18\x13 \x01(\t\x12\x65\n&propagated_nexus_serialization_context\x18\x14 \x01(\x0b\x32\x35.temporal.api.nexus.v1.PropagatedSerializationContext\x1aT\n\x11HeaderFieldsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12.\n\x05value\x18\x02 \x01(\x0b\x32\x1f.temporal.api.common.v1.Payload:\x02\x38\x01"\x8a\x01\n\x06\x43\x61ncel\x12;\n\x06reason\x18\x01 \x01(\x0e\x32+.coresdk.activity_task.ActivityCancelReason\x12\x43\n\x07\x64\x65tails\x18\x02 \x01(\x0b\x32\x32.coresdk.activity_task.ActivityCancellationDetails"\xa0\x01\n\x1b\x41\x63tivityCancellationDetails\x12\x14\n\x0cis_not_found\x18\x01 \x01(\x08\x12\x14\n\x0cis_cancelled\x18\x02 \x01(\x08\x12\x11\n\tis_paused\x18\x03 \x01(\x08\x12\x14\n\x0cis_timed_out\x18\x04 \x01(\x08\x12\x1a\n\x12is_worker_shutdown\x18\x05 \x01(\x08\x12\x10\n\x08is_reset\x18\x06 \x01(\x08*o\n\x14\x41\x63tivityCancelReason\x12\r\n\tNOT_FOUND\x10\x00\x12\r\n\tCANCELLED\x10\x01\x12\r\n\tTIMED_OUT\x10\x02\x12\x13\n\x0fWORKER_SHUTDOWN\x10\x03\x12\n\n\x06PAUSED\x10\x04\x12\t\n\x05RESET\x10\x05\x42\x32\xea\x02/Temporalio::Internal::Bridge::Api::ActivityTaskb\x06proto3' + b'\n3temporal/sdk/core/activity_task/activity_task.proto\x12\x15\x63oresdk.activity_task\x1a\x1egoogle/protobuf/duration.proto\x1a\x1fgoogle/protobuf/timestamp.proto\x1a$temporal/api/common/v1/message.proto\x1a#temporal/api/nexus/v1/message.proto\x1a%temporal/sdk/core/common/common.proto"\x8d\x01\n\x0c\x41\x63tivityTask\x12\x12\n\ntask_token\x18\x01 \x01(\x0c\x12-\n\x05start\x18\x03 \x01(\x0b\x32\x1c.coresdk.activity_task.StartH\x00\x12/\n\x06\x63\x61ncel\x18\x04 \x01(\x0b\x32\x1d.coresdk.activity_task.CancelH\x00\x42\t\n\x07variant"\xdb\x08\n\x05Start\x12\x1a\n\x12workflow_namespace\x18\x01 \x01(\t\x12\x15\n\rworkflow_type\x18\x02 \x01(\t\x12\x45\n\x12workflow_execution\x18\x03 \x01(\x0b\x32).temporal.api.common.v1.WorkflowExecution\x12\x13\n\x0b\x61\x63tivity_id\x18\x04 \x01(\t\x12\x15\n\ractivity_type\x18\x05 \x01(\t\x12\x45\n\rheader_fields\x18\x06 \x03(\x0b\x32..coresdk.activity_task.Start.HeaderFieldsEntry\x12.\n\x05input\x18\x07 \x03(\x0b\x32\x1f.temporal.api.common.v1.Payload\x12:\n\x11heartbeat_details\x18\x08 \x03(\x0b\x32\x1f.temporal.api.common.v1.Payload\x12\x32\n\x0escheduled_time\x18\t \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x42\n\x1e\x63urrent_attempt_scheduled_time\x18\n \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x30\n\x0cstarted_time\x18\x0b \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x0f\n\x07\x61ttempt\x18\x0c \x01(\r\x12<\n\x19schedule_to_close_timeout\x18\r \x01(\x0b\x32\x19.google.protobuf.Duration\x12\x39\n\x16start_to_close_timeout\x18\x0e \x01(\x0b\x32\x19.google.protobuf.Duration\x12\x34\n\x11heartbeat_timeout\x18\x0f \x01(\x0b\x32\x19.google.protobuf.Duration\x12\x39\n\x0cretry_policy\x18\x10 \x01(\x0b\x32#.temporal.api.common.v1.RetryPolicy\x12\x32\n\x08priority\x18\x12 \x01(\x0b\x32 .temporal.api.common.v1.Priority\x12\x10\n\x08is_local\x18\x11 \x01(\x08\x12\x0e\n\x06run_id\x18\x13 \x01(\t\x12\x65\n&propagated_nexus_serialization_context\x18\x14 \x01(\x0b\x32\x35.temporal.api.nexus.v1.PropagatedSerializationContext\x12\x41\n\rworkflow_task\x18\x15 \x01(\x0b\x32*.coresdk.activity_task.WorkflowTaskAttempt\x1aT\n\x11HeaderFieldsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12.\n\x05value\x18\x02 \x01(\x0b\x32\x1f.temporal.api.common.v1.Payload:\x02\x38\x01"\x80\x02\n\x13WorkflowTaskAttempt\x12\x18\n\x10started_event_id\x18\x01 \x01(\x03\x12\x0f\n\x07\x61ttempt\x18\x02 \x01(\r\x12\x30\n\x0cstarted_time\x18\x03 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12!\n\x19previous_started_event_id\x18\x04 \x01(\x03\x12\x14\n\x0c\x66\x61iled_tasks\x18\x05 \x03(\x03\x12\x18\n\x10previous_attempt\x18\x06 \x01(\r\x12\x39\n\x15previous_started_time\x18\x07 \x01(\x0b\x32\x1a.google.protobuf.Timestamp"\x8a\x01\n\x06\x43\x61ncel\x12;\n\x06reason\x18\x01 \x01(\x0e\x32+.coresdk.activity_task.ActivityCancelReason\x12\x43\n\x07\x64\x65tails\x18\x02 \x01(\x0b\x32\x32.coresdk.activity_task.ActivityCancellationDetails"\xa0\x01\n\x1b\x41\x63tivityCancellationDetails\x12\x14\n\x0cis_not_found\x18\x01 \x01(\x08\x12\x14\n\x0cis_cancelled\x18\x02 \x01(\x08\x12\x11\n\tis_paused\x18\x03 \x01(\x08\x12\x14\n\x0cis_timed_out\x18\x04 \x01(\x08\x12\x1a\n\x12is_worker_shutdown\x18\x05 \x01(\x08\x12\x10\n\x08is_reset\x18\x06 \x01(\x08*o\n\x14\x41\x63tivityCancelReason\x12\r\n\tNOT_FOUND\x10\x00\x12\r\n\tCANCELLED\x10\x01\x12\r\n\tTIMED_OUT\x10\x02\x12\x13\n\x0fWORKER_SHUTDOWN\x10\x03\x12\n\n\x06PAUSED\x10\x04\x12\t\n\x05RESET\x10\x05\x42\x32\xea\x02/Temporalio::Internal::Bridge::Api::ActivityTaskb\x06proto3' ) _ACTIVITYCANCELREASON = DESCRIPTOR.enum_types_by_name["ActivityCancelReason"] @@ -45,6 +45,7 @@ _ACTIVITYTASK = DESCRIPTOR.message_types_by_name["ActivityTask"] _START = DESCRIPTOR.message_types_by_name["Start"] _START_HEADERFIELDSENTRY = _START.nested_types_by_name["HeaderFieldsEntry"] +_WORKFLOWTASKATTEMPT = DESCRIPTOR.message_types_by_name["WorkflowTaskAttempt"] _CANCEL = DESCRIPTOR.message_types_by_name["Cancel"] _ACTIVITYCANCELLATIONDETAILS = DESCRIPTOR.message_types_by_name[ "ActivityCancellationDetails" @@ -81,6 +82,17 @@ _sym_db.RegisterMessage(Start) _sym_db.RegisterMessage(Start.HeaderFieldsEntry) +WorkflowTaskAttempt = _reflection.GeneratedProtocolMessageType( + "WorkflowTaskAttempt", + (_message.Message,), + { + "DESCRIPTOR": _WORKFLOWTASKATTEMPT, + "__module__": "temporal.sdk.core.activity_task.activity_task_pb2", + # @@protoc_insertion_point(class_scope:coresdk.activity_task.WorkflowTaskAttempt) + }, +) +_sym_db.RegisterMessage(WorkflowTaskAttempt) + Cancel = _reflection.GeneratedProtocolMessageType( "Cancel", (_message.Message,), @@ -110,16 +122,18 @@ ) _START_HEADERFIELDSENTRY._options = None _START_HEADERFIELDSENTRY._serialized_options = b"8\001" - _ACTIVITYCANCELREASON._serialized_start = 1756 - _ACTIVITYCANCELREASON._serialized_end = 1867 + _ACTIVITYCANCELREASON._serialized_start = 2082 + _ACTIVITYCANCELREASON._serialized_end = 2193 _ACTIVITYTASK._serialized_start = 258 _ACTIVITYTASK._serialized_end = 399 _START._serialized_start = 402 - _START._serialized_end = 1450 - _START_HEADERFIELDSENTRY._serialized_start = 1366 - _START_HEADERFIELDSENTRY._serialized_end = 1450 - _CANCEL._serialized_start = 1453 - _CANCEL._serialized_end = 1591 - _ACTIVITYCANCELLATIONDETAILS._serialized_start = 1594 - _ACTIVITYCANCELLATIONDETAILS._serialized_end = 1754 + _START._serialized_end = 1517 + _START_HEADERFIELDSENTRY._serialized_start = 1433 + _START_HEADERFIELDSENTRY._serialized_end = 1517 + _WORKFLOWTASKATTEMPT._serialized_start = 1520 + _WORKFLOWTASKATTEMPT._serialized_end = 1776 + _CANCEL._serialized_start = 1779 + _CANCEL._serialized_end = 1917 + _ACTIVITYCANCELLATIONDETAILS._serialized_start = 1920 + _ACTIVITYCANCELLATIONDETAILS._serialized_end = 2080 # @@protoc_insertion_point(module_scope) diff --git a/temporalio/bridge/proto/activity_task/activity_task_pb2.pyi b/temporalio/bridge/proto/activity_task/activity_task_pb2.pyi index fd17611e2..960c984f2 100644 --- a/temporalio/bridge/proto/activity_task/activity_task_pb2.pyi +++ b/temporalio/bridge/proto/activity_task/activity_task_pb2.pyi @@ -162,6 +162,7 @@ class Start(google.protobuf.message.Message): IS_LOCAL_FIELD_NUMBER: builtins.int RUN_ID_FIELD_NUMBER: builtins.int PROPAGATED_NEXUS_SERIALIZATION_CONTEXT_FIELD_NUMBER: builtins.int + WORKFLOW_TASK_FIELD_NUMBER: builtins.int workflow_namespace: builtins.str """The namespace the workflow lives in""" workflow_type: builtins.str @@ -237,6 +238,11 @@ class Start(google.protobuf.message.Message): Only set for standalone activities. Lang should use it to serialize the activity's result and failure, which are returned to the Nexus caller. """ + @property + def workflow_task(self) -> global___WorkflowTaskAttempt: + """For a local activity, the workflow task in which Core dispatched this execution. Retries that + Core runs locally keep the value. Unset for other activities. + """ def __init__( self, *, @@ -270,6 +276,7 @@ class Start(google.protobuf.message.Message): run_id: builtins.str = ..., propagated_nexus_serialization_context: temporalio.api.nexus.v1.message_pb2.PropagatedSerializationContext | None = ..., + workflow_task: global___WorkflowTaskAttempt | None = ..., ) -> None: ... def HasField( self, @@ -294,6 +301,8 @@ class Start(google.protobuf.message.Message): b"started_time", "workflow_execution", b"workflow_execution", + "workflow_task", + b"workflow_task", ], ) -> builtins.bool: ... def ClearField( @@ -337,6 +346,8 @@ class Start(google.protobuf.message.Message): b"workflow_execution", "workflow_namespace", b"workflow_namespace", + "workflow_task", + b"workflow_task", "workflow_type", b"workflow_type", ], @@ -344,6 +355,83 @@ class Start(google.protobuf.message.Message): global___Start = Start +class WorkflowTaskAttempt(google.protobuf.message.Message): + """One attempt of a workflow task, from the poll response and the history of that attempt.""" + + DESCRIPTOR: google.protobuf.descriptor.Descriptor + + STARTED_EVENT_ID_FIELD_NUMBER: builtins.int + ATTEMPT_FIELD_NUMBER: builtins.int + STARTED_TIME_FIELD_NUMBER: builtins.int + PREVIOUS_STARTED_EVENT_ID_FIELD_NUMBER: builtins.int + FAILED_TASKS_FIELD_NUMBER: builtins.int + PREVIOUS_ATTEMPT_FIELD_NUMBER: builtins.int + PREVIOUS_STARTED_TIME_FIELD_NUMBER: builtins.int + started_event_id: builtins.int + """The event id of the task's WorkflowTaskStarted event.""" + attempt: builtins.int + @property + def started_time(self) -> google.protobuf.timestamp_pb2.Timestamp: + """When the server started the task.""" + previous_started_event_id: builtins.int + """The started event id of the run's last completed workflow task, from the poll response. + 0 when no task of the run has completed. + """ + @property + def failed_tasks( + self, + ) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[builtins.int]: + """The started event ids of the run's last 100 failed and timed out workflow tasks in history, + in event order. The cap keeps each start small. A transient attempt has no such event. + """ + previous_attempt: builtins.int + """The attempt and the started time of the task at previous_started_event_id, from its + WorkflowTaskScheduled and WorkflowTaskStarted events. Unset when no task has completed. + """ + @property + def previous_started_time(self) -> google.protobuf.timestamp_pb2.Timestamp: ... + def __init__( + self, + *, + started_event_id: builtins.int = ..., + attempt: builtins.int = ..., + started_time: google.protobuf.timestamp_pb2.Timestamp | None = ..., + previous_started_event_id: builtins.int = ..., + failed_tasks: collections.abc.Iterable[builtins.int] | None = ..., + previous_attempt: builtins.int = ..., + previous_started_time: google.protobuf.timestamp_pb2.Timestamp | None = ..., + ) -> None: ... + def HasField( + self, + field_name: typing_extensions.Literal[ + "previous_started_time", + b"previous_started_time", + "started_time", + b"started_time", + ], + ) -> builtins.bool: ... + def ClearField( + self, + field_name: typing_extensions.Literal[ + "attempt", + b"attempt", + "failed_tasks", + b"failed_tasks", + "previous_attempt", + b"previous_attempt", + "previous_started_event_id", + b"previous_started_event_id", + "previous_started_time", + b"previous_started_time", + "started_event_id", + b"started_event_id", + "started_time", + b"started_time", + ], + ) -> None: ... + +global___WorkflowTaskAttempt = WorkflowTaskAttempt + class Cancel(google.protobuf.message.Message): """Attempt to cancel a running activity""" diff --git a/temporalio/bridge/sdk-core b/temporalio/bridge/sdk-core index f49305f18..ff30d403d 160000 --- a/temporalio/bridge/sdk-core +++ b/temporalio/bridge/sdk-core @@ -1 +1 @@ -Subproject commit f49305f18ebd724668d5f86bf715b5ffe59287f2 +Subproject commit ff30d403dc4fcf35b888677f25b96bdbda88d323