From 181d052558a750032a1b95de96961ba9987e00fe Mon Sep 17 00:00:00 2001 From: chaptersix <13949480+chaptersix@users.noreply.github.com> Date: Fri, 4 Sep 2026 21:43:18 -0500 Subject: [PATCH 1/3] Add extensible schedule action API --- temporal/api/common/v1/message.proto | 12 ++++++ temporal/api/schedule/v1/message.proto | 57 ++++++++++++++++++++++++++ 2 files changed, 69 insertions(+) diff --git a/temporal/api/common/v1/message.proto b/temporal/api/common/v1/message.proto index 3e2fc0e1c..01d8f7567 100644 --- a/temporal/api/common/v1/message.proto +++ b/temporal/api/common/v1/message.proto @@ -14,8 +14,10 @@ import "google/protobuf/empty.proto"; import "google/protobuf/timestamp.proto"; import "temporal/api/enums/v1/common.proto"; +import "temporal/api/enums/v1/activity.proto"; import "temporal/api/enums/v1/event_type.proto"; import "temporal/api/enums/v1/reset.proto"; +import "temporal/api/enums/v1/workflow.proto"; message DataBlob { temporal.api.enums.v1.EncodingType encoding_type = 1; @@ -76,6 +78,16 @@ message Execution { string run_id = 3; } +// Identifies an execution started by an action and reports its current status. +message ActionExecutionResult { + Execution execution = 1; + + oneof status { + temporal.api.enums.v1.WorkflowExecutionStatus workflow_status = 2; + temporal.api.enums.v1.ActivityExecutionStatus activity_status = 3; + } +} + // Represents the identifier used by a workflow author to define the workflow. Typically, the // name of a function. This is sometimes referred to as the workflow's "name" message WorkflowType { diff --git a/temporal/api/schedule/v1/message.proto b/temporal/api/schedule/v1/message.proto index 3a0a9344c..668ad97f7 100644 --- a/temporal/api/schedule/v1/message.proto +++ b/temporal/api/schedule/v1/message.proto @@ -18,8 +18,11 @@ import "google/protobuf/duration.proto"; import "google/protobuf/timestamp.proto"; import "temporal/api/common/v1/message.proto"; +import "temporal/api/enums/v1/common.proto"; import "temporal/api/enums/v1/schedule.proto"; import "temporal/api/enums/v1/workflow.proto"; +import "temporal/api/sdk/v1/user_metadata.proto"; +import "temporal/api/taskqueue/v1/message.proto"; import "temporal/api/workflow/v1/message.proto"; // CalendarSpec describes an event specification relative to the calendar, @@ -227,6 +230,34 @@ message SchedulePolicies { // If true, and the action would start a workflow, a timestamp will not be // appended to the scheduled workflow id. bool keep_original_workflow_id = 4; + + // A named overlap policy registered by the action implementation. This may not be set together + // with overlap_policy. + CustomOverlapPolicy custom_overlap_policy = 5; +} + +// Selects an overlap policy registered by an action implementation. +message CustomOverlapPolicy { + string name = 1; +} + +// Describes a standalone activity that a schedule starts. +message StartActivityExecutionInfo { + // The activity ID may have a timestamp appended for uniqueness. + string activity_id = 1; + temporal.api.common.v1.ActivityType activity_type = 2; + temporal.api.taskqueue.v1.TaskQueue task_queue = 3; + google.protobuf.Duration schedule_to_close_timeout = 4; + google.protobuf.Duration schedule_to_start_timeout = 5; + google.protobuf.Duration start_to_close_timeout = 6; + google.protobuf.Duration heartbeat_timeout = 7; + temporal.api.common.v1.RetryPolicy retry_policy = 8; + temporal.api.common.v1.Payloads input = 9; + temporal.api.common.v1.SearchAttributes search_attributes = 10; + temporal.api.common.v1.Header header = 11; + temporal.api.sdk.v1.UserMetadata user_metadata = 12; + temporal.api.common.v1.Priority priority = 13; + google.protobuf.Duration start_delay = 14; } message ScheduleAction { @@ -237,6 +268,7 @@ message ScheduleAction { // The workflow id of the started workflow may not match this exactly, // it may have a timestamp appended for uniqueness. temporal.api.workflow.v1.NewWorkflowExecutionInfo start_workflow = 1; + StartActivityExecutionInfo start_activity = 2; } } @@ -253,6 +285,12 @@ message ScheduleActionResult { // If the action was start_workflow, this field will reflect an // eventually-consistent view of the started workflow's status. temporal.api.enums.v1.WorkflowExecutionStatus start_workflow_status = 12; + + // The execution started by this action and its current status. + temporal.api.common.v1.ActionExecutionResult action_execution_result = 13; + + // Time the execution reached a terminal status, if known. + google.protobuf.Timestamp close_time = 14; } message ScheduleState { @@ -282,6 +320,9 @@ message TriggerImmediatelyRequest { // Timestamp used for the identity of the target workflow. // If not set the default value is the current time. google.protobuf.Timestamp scheduled_time = 2; + + // If set, override overlap policy for this request. This may not be set together with overlap_policy. + CustomOverlapPolicy custom_overlap_policy = 3; } message BackfillRequest { @@ -295,6 +336,8 @@ message BackfillRequest { google.protobuf.Timestamp end_time = 2; // If set, override overlap policy for this request. temporal.api.enums.v1.ScheduleOverlapPolicy overlap_policy = 3; + // If set, override overlap policy for this request. This may not be set together with overlap_policy. + CustomOverlapPolicy custom_overlap_policy = 4; } message SchedulePatch { @@ -352,6 +395,13 @@ message ScheduleInfo { // Size of the schedule's internal state (including payloads) in bytes. int64 state_size_bytes = 12; + + // Currently-running executions started by this schedule. + repeated temporal.api.common.v1.Execution running_executions = 13; + + // Kind and registered type of the action. + temporal.api.enums.v1.ExecutionType action_kind = 14; + string action_type = 15; } message Schedule { @@ -383,6 +433,13 @@ message ScheduleListInfo { // Size of the schedule's internal state (including payloads) in bytes. int64 state_size_bytes = 7; + + // Kind and registered type of the action. + temporal.api.enums.v1.ExecutionType action_kind = 8; + string action_type = 9; + + // Number of tracked running executions started by the schedule. + int64 running_execution_count = 10; } // ScheduleListEntry is returned by ListSchedules. From e4b2f8ed6746de8d6c1966cef73b8ee91c2db6d0 Mon Sep 17 00:00:00 2001 From: chaptersix <13949480+chaptersix@users.noreply.github.com> Date: Fri, 4 Sep 2026 22:23:51 -0500 Subject: [PATCH 2/3] Regenerate schedule OpenAPI schemas --- openapi/openapiv2.json | 124 ++++++++++++++++++++++++++++++++++++++++ openapi/openapiv3.yaml | 127 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 251 insertions(+) diff --git a/openapi/openapiv2.json b/openapi/openapiv2.json index bb5acc172..ce5698727 100644 --- a/openapi/openapiv2.json +++ b/openapi/openapiv2.json @@ -13623,6 +13623,21 @@ } } }, + "v1ActionExecutionResult": { + "type": "object", + "properties": { + "execution": { + "$ref": "#/definitions/v1Execution" + }, + "workflowStatus": { + "$ref": "#/definitions/v1WorkflowExecutionStatus" + }, + "activityStatus": { + "$ref": "#/definitions/v1ActivityExecutionStatus" + } + }, + "description": "Identifies an execution started by an action and reports its current status." + }, "v1ActivityExecutionInfo": { "type": "object", "properties": { @@ -14286,6 +14301,10 @@ "overlapPolicy": { "$ref": "#/definitions/v1ScheduleOverlapPolicy", "description": "If set, override overlap policy for this request." + }, + "customOverlapPolicy": { + "$ref": "#/definitions/v1CustomOverlapPolicy", + "description": "If set, override overlap policy for this request. This may not be set together with overlap_policy." } } }, @@ -15336,6 +15355,15 @@ } } }, + "v1CustomOverlapPolicy": { + "type": "object", + "properties": { + "name": { + "type": "string" + } + }, + "description": "Selects an overlap policy registered by an action implementation." + }, "v1DataBlob": { "type": "object", "properties": { @@ -19186,6 +19214,9 @@ "startWorkflow": { "$ref": "#/definitions/v1NewWorkflowExecutionInfo", "description": "All fields of NewWorkflowExecutionInfo are valid except for:\n- workflow_id_reuse_policy\n- cron_schedule\nThe workflow id of the started workflow may not match this exactly,\nit may have a timestamp appended for uniqueness." + }, + "startActivity": { + "$ref": "#/definitions/v1StartActivityExecutionInfo" } } }, @@ -19209,6 +19240,15 @@ "startWorkflowStatus": { "$ref": "#/definitions/v1WorkflowExecutionStatus", "description": "If the action was start_workflow, this field will reflect an\neventually-consistent view of the started workflow's status." + }, + "actionExecutionResult": { + "$ref": "#/definitions/v1ActionExecutionResult", + "description": "The execution started by this action and its current status." + }, + "closeTime": { + "type": "string", + "format": "date-time", + "description": "Time the execution reached a terminal status, if known." } } }, @@ -19281,6 +19321,21 @@ "type": "string", "format": "int64", "description": "Size of the schedule's internal state (including payloads) in bytes." + }, + "runningExecutions": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/v1Execution" + }, + "description": "Currently-running executions started by this schedule." + }, + "actionKind": { + "$ref": "#/definitions/v1ExecutionType", + "description": "Kind and registered type of the action." + }, + "actionType": { + "type": "string" } } }, @@ -19339,6 +19394,18 @@ "type": "string", "format": "int64", "description": "Size of the schedule's internal state (including payloads) in bytes." + }, + "actionKind": { + "$ref": "#/definitions/v1ExecutionType", + "description": "Kind and registered type of the action." + }, + "actionType": { + "type": "string" + }, + "runningExecutionCount": { + "type": "string", + "format": "int64", + "description": "Number of tracked running executions started by the schedule." } }, "description": "ScheduleListInfo is an abbreviated set of values from Schedule and ScheduleInfo\nthat's returned in ListSchedules." @@ -19399,6 +19466,10 @@ "keepOriginalWorkflowId": { "type": "boolean", "description": "If true, and the action would start a workflow, a timestamp will not be\nappended to the scheduled workflow id." + }, + "customOverlapPolicy": { + "$ref": "#/definitions/v1CustomOverlapPolicy", + "description": "A named overlap policy registered by the action implementation. This may not be set together\nwith overlap_policy." } } }, @@ -19706,6 +19777,55 @@ } } }, + "v1StartActivityExecutionInfo": { + "type": "object", + "properties": { + "activityId": { + "type": "string", + "description": "The activity ID may have a timestamp appended for uniqueness." + }, + "activityType": { + "$ref": "#/definitions/v1ActivityType" + }, + "taskQueue": { + "$ref": "#/definitions/v1TaskQueue" + }, + "scheduleToCloseTimeout": { + "type": "string" + }, + "scheduleToStartTimeout": { + "type": "string" + }, + "startToCloseTimeout": { + "type": "string" + }, + "heartbeatTimeout": { + "type": "string" + }, + "retryPolicy": { + "$ref": "#/definitions/v1RetryPolicy" + }, + "input": { + "$ref": "#/definitions/v1Payloads" + }, + "searchAttributes": { + "$ref": "#/definitions/v1SearchAttributes" + }, + "header": { + "$ref": "#/definitions/v1Header" + }, + "userMetadata": { + "$ref": "#/definitions/v1UserMetadata" + }, + "priority": { + "$ref": "#/definitions/v1Priority" + }, + "startDelay": { + "type": "string" + } + }, + "description": "Describes a standalone activity that a schedule starts." + }, "v1StartActivityExecutionResponse": { "type": "object", "properties": { @@ -20450,6 +20570,10 @@ "type": "string", "format": "date-time", "description": "Timestamp used for the identity of the target workflow.\nIf not set the default value is the current time." + }, + "customOverlapPolicy": { + "$ref": "#/definitions/v1CustomOverlapPolicy", + "description": "If set, override overlap policy for this request. This may not be set together with overlap_policy." } } }, diff --git a/openapi/openapiv3.yaml b/openapi/openapiv3.yaml index 1d4c2cdc0..82f0d41ba 100644 --- a/openapi/openapiv3.yaml +++ b/openapi/openapiv3.yaml @@ -9722,6 +9722,37 @@ paths: $ref: '#/components/schemas/Status' components: schemas: + ActionExecutionResult: + type: object + properties: + execution: + $ref: '#/components/schemas/Execution' + workflowStatus: + enum: + - WORKFLOW_EXECUTION_STATUS_UNSPECIFIED + - WORKFLOW_EXECUTION_STATUS_RUNNING + - WORKFLOW_EXECUTION_STATUS_COMPLETED + - WORKFLOW_EXECUTION_STATUS_FAILED + - WORKFLOW_EXECUTION_STATUS_CANCELED + - WORKFLOW_EXECUTION_STATUS_TERMINATED + - WORKFLOW_EXECUTION_STATUS_CONTINUED_AS_NEW + - WORKFLOW_EXECUTION_STATUS_TIMED_OUT + - WORKFLOW_EXECUTION_STATUS_PAUSED + type: string + format: enum + activityStatus: + enum: + - ACTIVITY_EXECUTION_STATUS_UNSPECIFIED + - ACTIVITY_EXECUTION_STATUS_RUNNING + - ACTIVITY_EXECUTION_STATUS_COMPLETED + - ACTIVITY_EXECUTION_STATUS_FAILED + - ACTIVITY_EXECUTION_STATUS_CANCELED + - ACTIVITY_EXECUTION_STATUS_TERMINATED + - ACTIVITY_EXECUTION_STATUS_TIMED_OUT + - ACTIVITY_EXECUTION_STATUS_PAUSED + type: string + format: enum + description: Identifies an execution started by an action and reports its current status. ActivityExecutionInfo: type: object properties: @@ -10412,6 +10443,10 @@ components: type: string description: If set, override overlap policy for this request. format: enum + customOverlapPolicy: + allOf: + - $ref: '#/components/schemas/CustomOverlapPolicy' + description: If set, override overlap policy for this request. This may not be set together with overlap_policy. BadBinaries: type: object properties: @@ -11569,6 +11604,12 @@ components: jobId: type: string description: Batch Job ID if force-scan flag was provided. Otherwise empty. + CustomOverlapPolicy: + type: object + properties: + name: + type: string + description: Selects an overlap policy registered by an action implementation. DataBlob: type: object properties: @@ -16091,6 +16132,8 @@ components: - cron_schedule The workflow id of the started workflow may not match this exactly, it may have a timestamp appended for uniqueness. + startActivity: + $ref: '#/components/schemas/StartActivityExecutionInfo' ScheduleActionResult: type: object properties: @@ -16122,6 +16165,14 @@ components: If the action was start_workflow, this field will reflect an eventually-consistent view of the started workflow's status. format: enum + actionExecutionResult: + allOf: + - $ref: '#/components/schemas/ActionExecutionResult' + description: The execution started by this action and its current status. + closeTime: + type: string + description: Time the execution reached a terminal status, if known. + format: date-time ScheduleInfo: type: object properties: @@ -16177,6 +16228,21 @@ components: stateSizeBytes: type: string description: Size of the schedule's internal state (including payloads) in bytes. + runningExecutions: + type: array + items: + $ref: '#/components/schemas/Execution' + description: Currently-running executions started by this schedule. + actionKind: + enum: + - EXECUTION_TYPE_UNSPECIFIED + - EXECUTION_TYPE_WORKFLOW + - EXECUTION_TYPE_ACTIVITY + type: string + description: Kind and registered type of the action. + format: enum + actionType: + type: string ScheduleListEntry: type: object properties: @@ -16223,6 +16289,19 @@ components: stateSizeBytes: type: string description: Size of the schedule's internal state (including payloads) in bytes. + actionKind: + enum: + - EXECUTION_TYPE_UNSPECIFIED + - EXECUTION_TYPE_WORKFLOW + - EXECUTION_TYPE_ACTIVITY + type: string + description: Kind and registered type of the action. + format: enum + actionType: + type: string + runningExecutionCount: + type: string + description: Number of tracked running executions started by the schedule. description: |- ScheduleListInfo is an abbreviated set of values from Schedule and ScheduleInfo that's returned in ListSchedules. @@ -16287,6 +16366,12 @@ components: description: |- If true, and the action would start a workflow, a timestamp will not be appended to the scheduled workflow id. + customOverlapPolicy: + allOf: + - $ref: '#/components/schemas/CustomOverlapPolicy' + description: |- + A named overlap policy registered by the action implementation. This may not be set together + with overlap_policy. ScheduleSpec: type: object properties: @@ -16924,6 +17009,44 @@ components: Link to be associated with the WorkflowExecutionSignaled event. Added on the response to propagate the backlink. Available from Temporal server 1.31 and up. + StartActivityExecutionInfo: + type: object + properties: + activityId: + type: string + description: The activity ID may have a timestamp appended for uniqueness. + activityType: + $ref: '#/components/schemas/ActivityType' + taskQueue: + $ref: '#/components/schemas/TaskQueue' + scheduleToCloseTimeout: + pattern: ^-?(?:0|[1-9][0-9]{0,11})(?:\.[0-9]{1,9})?s$ + type: string + scheduleToStartTimeout: + pattern: ^-?(?:0|[1-9][0-9]{0,11})(?:\.[0-9]{1,9})?s$ + type: string + startToCloseTimeout: + pattern: ^-?(?:0|[1-9][0-9]{0,11})(?:\.[0-9]{1,9})?s$ + type: string + heartbeatTimeout: + pattern: ^-?(?:0|[1-9][0-9]{0,11})(?:\.[0-9]{1,9})?s$ + type: string + retryPolicy: + $ref: '#/components/schemas/RetryPolicy' + input: + $ref: '#/components/schemas/Payloads' + searchAttributes: + $ref: '#/components/schemas/SearchAttributes' + header: + $ref: '#/components/schemas/Header' + userMetadata: + $ref: '#/components/schemas/UserMetadata' + priority: + $ref: '#/components/schemas/Priority' + startDelay: + pattern: ^-?(?:0|[1-9][0-9]{0,11})(?:\.[0-9]{1,9})?s$ + type: string + description: Describes a standalone activity that a schedule starts. StartActivityExecutionRequest: type: object properties: @@ -18150,6 +18273,10 @@ components: Timestamp used for the identity of the target workflow. If not set the default value is the current time. format: date-time + customOverlapPolicy: + allOf: + - $ref: '#/components/schemas/CustomOverlapPolicy' + description: If set, override overlap policy for this request. This may not be set together with overlap_policy. TriggerWorkflowRuleRequest: type: object properties: From 40766d34ea6c0d2e59c100c1cf20cdf4fb286fe4 Mon Sep 17 00:00:00 2001 From: chaptersix <13949480+chaptersix@users.noreply.github.com> Date: Fri, 4 Sep 2026 22:26:32 -0500 Subject: [PATCH 3/3] Annotate schedule activity timeouts --- openapi/openapiv3.yaml | 9 +++++++++ temporal/api/schedule/v1/message.proto | 6 ++++++ 2 files changed, 15 insertions(+) diff --git a/openapi/openapiv3.yaml b/openapi/openapiv3.yaml index 82f0d41ba..008e7ee1d 100644 --- a/openapi/openapiv3.yaml +++ b/openapi/openapiv3.yaml @@ -17022,12 +17022,21 @@ components: scheduleToCloseTimeout: pattern: ^-?(?:0|[1-9][0-9]{0,11})(?:\.[0-9]{1,9})?s$ type: string + description: |- + (-- api-linter: core::0140::prepositions=disabled + aip.dev/not-precedent: "to" is used to indicate interval. --) scheduleToStartTimeout: pattern: ^-?(?:0|[1-9][0-9]{0,11})(?:\.[0-9]{1,9})?s$ type: string + description: |- + (-- api-linter: core::0140::prepositions=disabled + aip.dev/not-precedent: "to" is used to indicate interval. --) startToCloseTimeout: pattern: ^-?(?:0|[1-9][0-9]{0,11})(?:\.[0-9]{1,9})?s$ type: string + description: |- + (-- api-linter: core::0140::prepositions=disabled + aip.dev/not-precedent: "to" is used to indicate interval. --) heartbeatTimeout: pattern: ^-?(?:0|[1-9][0-9]{0,11})(?:\.[0-9]{1,9})?s$ type: string diff --git a/temporal/api/schedule/v1/message.proto b/temporal/api/schedule/v1/message.proto index 668ad97f7..735f82b2f 100644 --- a/temporal/api/schedule/v1/message.proto +++ b/temporal/api/schedule/v1/message.proto @@ -247,8 +247,14 @@ message StartActivityExecutionInfo { string activity_id = 1; temporal.api.common.v1.ActivityType activity_type = 2; temporal.api.taskqueue.v1.TaskQueue task_queue = 3; + // (-- api-linter: core::0140::prepositions=disabled + // aip.dev/not-precedent: "to" is used to indicate interval. --) google.protobuf.Duration schedule_to_close_timeout = 4; + // (-- api-linter: core::0140::prepositions=disabled + // aip.dev/not-precedent: "to" is used to indicate interval. --) google.protobuf.Duration schedule_to_start_timeout = 5; + // (-- api-linter: core::0140::prepositions=disabled + // aip.dev/not-precedent: "to" is used to indicate interval. --) google.protobuf.Duration start_to_close_timeout = 6; google.protobuf.Duration heartbeat_timeout = 7; temporal.api.common.v1.RetryPolicy retry_policy = 8;