Skip to content

Commit 9e2c2cb

Browse files
authored
api changes for time-skipping propagation (#770)
**What changed and why?** Propagation refers to how time-skipping config is carried over to all workflows started by the current workflow: retry, continue-as-new, child workflows, reset, etc. 1. Remove **disable_propagation** and **max_target_time**, because neither of them can be soundly defined when time-skipping propagates transitively across related workflows. One of the many examples: - max_target_time: as an absolute time point, it may already have passed by the time a retry or downstream workflow starts, making it ambiguous whether to disable or preserve time-skipping — neither is a clearly correct default - disable_propagation: it is unclear which type of transitively triggered workflow this should apply to, and treating all cases uniformly is unreasonable; we defer exposing this flexibility until user demand and use cases are better understood 2. Add **comments of the propagation behavior** for each feature (retry, continue-as-new, child workflow, reset, cron) 3. Add **comments to the bound field** 4. Add **propagatedSkippedDuration** to time skipping config so that new workflows can inherit the virtual time ** Breaking changes to API ** 1. deleted fields and reused the numbers since the TimeSkippingConfig is not yet released
1 parent 3a30adc commit 9e2c2cb

5 files changed

Lines changed: 67 additions & 54 deletions

File tree

openapi/openapiv2.json

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -17965,6 +17965,14 @@
1796517965
"priority": {
1796617966
"$ref": "#/definitions/v1Priority",
1796717967
"title": "Priority metadata"
17968+
},
17969+
"timeSkippingConfig": {
17970+
"$ref": "#/definitions/v1TimeSkippingConfig",
17971+
"description": "The propagated time-skipping configuration for the child workflow."
17972+
},
17973+
"initialSkippedDuration": {
17974+
"type": "string",
17975+
"description": "Propagate the duration skipped to the child workflow."
1796817976
}
1796917977
}
1797017978
},
@@ -18353,11 +18361,7 @@
1835318361
"properties": {
1835418362
"enabled": {
1835518363
"type": "boolean",
18356-
"description": "Enables or disables time skipping for this workflow execution.\nBy default, this field is propagated to transitively related workflows (child workflows/start-as-new/reset) \nat the time they are started.\nChanges made after a transitively related workflow has started are not propagated."
18357-
},
18358-
"disablePropagation": {
18359-
"type": "boolean",
18360-
"description": "If set, the enabled field is not propagated to transitively related workflows."
18364+
"description": "Enables or disables time skipping for this workflow execution."
1836118365
},
1836218366
"maxSkippedDuration": {
1836318367
"type": "string",
@@ -18366,14 +18370,9 @@
1836618370
"maxElapsedDuration": {
1836718371
"type": "string",
1836818372
"description": "Maximum elapsed time since time skipping was enabled.\nThis includes both skipped time and real time elapsing."
18369-
},
18370-
"maxTargetTime": {
18371-
"type": "string",
18372-
"format": "date-time",
18373-
"description": "Absolute virtual timestamp at which time skipping is disabled.\nTime skipping will not advance beyond this point."
1837418373
}
1837518374
},
18376-
"description": "Configuration for time skipping during a workflow execution.\nWhen enabled, virtual time advances automatically whenever there is no in-flight work.\nIn-flight work includes activities, child workflows, Nexus operations, signal/cancel external workflow operations,\nand possibly other features added in the future.\nUser timers are not classified as in-flight work and will be skipped over.\nWhen time advances, it skips to the earlier of the next user timer or the configured bound, if either exists."
18375+
"description": "Configuration for time skipping during a workflow execution.\nWhen enabled, virtual time advances automatically whenever there is no in-flight work.\nIn-flight work includes activities, child workflows, Nexus operations, signal/cancel external workflow operations,\nand possibly other features added in the future.\nUser timers are not classified as in-flight work and will be skipped over.\nWhen time advances, it skips to the earlier of the next user timer or the configured bound, if either exists.\n\nPropagation behavior of time skipping:\nThe enabled flag, bound fields, and accumulated skipped duration are propagated to related executions as follows:\n(1) Child workflows and continue-as-new: both the configuration and the accumulated skipped duration are\n inherited from the current execution. The configured bound is shared between the inherited skipped\n duration and any additional duration skipped by the new run.\n(2) Retry and cron: the configuration and accumulated skipped duration are inherited as recorded when the\n current workflow started; the accumulated skipped duration of the current run is not propagated.\n(3) Reset: the new run retains the time-skipping configuration of the current execution. Because reset replays\n all events up to the reset point and re-applies any UpdateWorkflowExecutionOptions changes made after that\n point, the resulting run ends up with the same final time-skipping configuration as the previous run."
1837718376
},
1837818377
"v1TimeoutFailureInfo": {
1837918378
"type": "object",
@@ -19657,7 +19656,7 @@
1965719656
},
1965819657
"timeSkippingConfig": {
1965919658
"$ref": "#/definitions/v1TimeSkippingConfig",
19660-
"description": "Time-skipping configuration for this workflow execution.\nIf not set, the time-skipping conf will not get updated upon request, \ni.e. the existing time-skipping conf will be preserved."
19659+
"description": "Time-skipping configuration for this workflow execution.\nIf not set, the time-skipping configuration is not updated by this request;\nthe existing configuration is preserved."
1966119660
}
1966219661
}
1966319662
},
@@ -19927,6 +19926,10 @@
1992719926
"timeSkippingConfig": {
1992819927
"$ref": "#/definitions/v1TimeSkippingConfig",
1992919928
"description": "Initial time-skipping configuration for this workflow execution, recorded at start time.\nThis may have been set explicitly via the start workflow request, or propagated from a\nparent/previous execution.\n\nThe configuration may be updated after start via UpdateWorkflowExecutionOptions, which\nwill be reflected in the WorkflowExecutionOptionsUpdatedEvent."
19929+
},
19930+
"initialSkippedDuration": {
19931+
"type": "string",
19932+
"description": "The time skipped by the previous execution that started this workflow.\nIt can happen in cases of child workflows and continue-as-new workflows."
1993019933
}
1993119934
},
1993219935
"title": "Always the first event in workflow history"

openapi/openapiv3.yaml

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -15557,6 +15557,14 @@ components:
1555715557
allOf:
1555815558
- $ref: '#/components/schemas/Priority'
1555915559
description: Priority metadata
15560+
timeSkippingConfig:
15561+
allOf:
15562+
- $ref: '#/components/schemas/TimeSkippingConfig'
15563+
description: The propagated time-skipping configuration for the child workflow.
15564+
initialSkippedDuration:
15565+
pattern: ^-?(?:0|[1-9][0-9]{0,11})(?:\.[0-9]{1,9})?s$
15566+
type: string
15567+
description: Propagate the duration skipped to the child workflow.
1556015568
StartNexusOperationExecutionRequest:
1556115569
type: object
1556215570
properties:
@@ -16243,10 +16251,7 @@ components:
1624316251
properties:
1624416252
enabled:
1624516253
type: boolean
16246-
description: "Enables or disables time skipping for this workflow execution.\n By default, this field is propagated to transitively related workflows (child workflows/start-as-new/reset) \n at the time they are started.\n Changes made after a transitively related workflow has started are not propagated."
16247-
disablePropagation:
16248-
type: boolean
16249-
description: If set, the enabled field is not propagated to transitively related workflows.
16254+
description: Enables or disables time skipping for this workflow execution.
1625016255
maxSkippedDuration:
1625116256
pattern: ^-?(?:0|[1-9][0-9]{0,11})(?:\.[0-9]{1,9})?s$
1625216257
type: string
@@ -16257,19 +16262,7 @@ components:
1625716262
description: |-
1625816263
Maximum elapsed time since time skipping was enabled.
1625916264
This includes both skipped time and real time elapsing.
16260-
maxTargetTime:
16261-
type: string
16262-
description: |-
16263-
Absolute virtual timestamp at which time skipping is disabled.
16264-
Time skipping will not advance beyond this point.
16265-
format: date-time
16266-
description: |-
16267-
Configuration for time skipping during a workflow execution.
16268-
When enabled, virtual time advances automatically whenever there is no in-flight work.
16269-
In-flight work includes activities, child workflows, Nexus operations, signal/cancel external workflow operations,
16270-
and possibly other features added in the future.
16271-
User timers are not classified as in-flight work and will be skipped over.
16272-
When time advances, it skips to the earlier of the next user timer or the configured bound, if either exists.
16265+
description: "Configuration for time skipping during a workflow execution.\n When enabled, virtual time advances automatically whenever there is no in-flight work.\n In-flight work includes activities, child workflows, Nexus operations, signal/cancel external workflow operations,\n and possibly other features added in the future.\n User timers are not classified as in-flight work and will be skipped over.\n When time advances, it skips to the earlier of the next user timer or the configured bound, if either exists.\n \n Propagation behavior of time skipping:\n The enabled flag, bound fields, and accumulated skipped duration are propagated to related executions as follows:\n (1) Child workflows and continue-as-new: both the configuration and the accumulated skipped duration are\n inherited from the current execution. The configured bound is shared between the inherited skipped\n duration and any additional duration skipped by the new run.\n (2) Retry and cron: the configuration and accumulated skipped duration are inherited as recorded when the\n current workflow started; the accumulated skipped duration of the current run is not propagated.\n (3) Reset: the new run retains the time-skipping configuration of the current execution. Because reset replays\n all events up to the reset point and re-applies any UpdateWorkflowExecutionOptions changes made after that\n point, the resulting run ends up with the same final time-skipping configuration as the previous run."
1627316266
TimeoutFailureInfo:
1627416267
type: object
1627516268
properties:
@@ -18219,7 +18212,10 @@ components:
1821918212
timeSkippingConfig:
1822018213
allOf:
1822118214
- $ref: '#/components/schemas/TimeSkippingConfig'
18222-
description: "Time-skipping configuration for this workflow execution.\n If not set, the time-skipping conf will not get updated upon request, \n i.e. the existing time-skipping conf will be preserved."
18215+
description: |-
18216+
Time-skipping configuration for this workflow execution.
18217+
If not set, the time-skipping configuration is not updated by this request;
18218+
the existing configuration is preserved.
1822318219
WorkflowExecutionOptionsUpdatedEventAttributes:
1822418220
type: object
1822518221
properties:
@@ -18563,6 +18559,12 @@ components:
1856318559

1856418560
The configuration may be updated after start via UpdateWorkflowExecutionOptions, which
1856518561
will be reflected in the WorkflowExecutionOptionsUpdatedEvent.
18562+
initialSkippedDuration:
18563+
pattern: ^-?(?:0|[1-9][0-9]{0,11})(?:\.[0-9]{1,9})?s$
18564+
type: string
18565+
description: |-
18566+
The time skipped by the previous execution that started this workflow.
18567+
It can happen in cases of child workflows and continue-as-new workflows.
1856618568
description: Always the first event in workflow history
1856718569
WorkflowExecutionTerminatedEventAttributes:
1856818570
type: object

temporal/api/history/v1/message.proto

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,10 @@ message WorkflowExecutionStartedEventAttributes {
204204
// The configuration may be updated after start via UpdateWorkflowExecutionOptions, which
205205
// will be reflected in the WorkflowExecutionOptionsUpdatedEvent.
206206
temporal.api.workflow.v1.TimeSkippingConfig time_skipping_config = 41;
207+
208+
// The time skipped by the previous execution that started this workflow.
209+
// It can happen in cases of child workflows and continue-as-new workflows.
210+
google.protobuf.Duration initial_skipped_duration = 42;
207211
}
208212

209213
// Wrapper for a target deployment version that the SDK declined to upgrade to.
@@ -770,6 +774,12 @@ message StartChildWorkflowExecutionInitiatedEventAttributes {
770774
bool inherit_build_id = 19 [deprecated = true];
771775
// Priority metadata
772776
temporal.api.common.v1.Priority priority = 20;
777+
778+
// The propagated time-skipping configuration for the child workflow.
779+
temporal.api.workflow.v1.TimeSkippingConfig time_skipping_config = 21;
780+
781+
// Propagate the duration skipped to the child workflow.
782+
google.protobuf.Duration initial_skipped_duration = 30;
773783
}
774784

775785
message StartChildWorkflowExecutionFailedEventAttributes {

temporal/api/workflow/v1/message.proto

Lines changed: 21 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -580,8 +580,8 @@ message WorkflowExecutionOptions {
580580
temporal.api.common.v1.Priority priority = 2;
581581

582582
// Time-skipping configuration for this workflow execution.
583-
// If not set, the time-skipping conf will not get updated upon request,
584-
// i.e. the existing time-skipping conf will be preserved.
583+
// If not set, the time-skipping configuration is not updated by this request;
584+
// the existing configuration is preserved.
585585
TimeSkippingConfig time_skipping_config = 3;
586586
}
587587

@@ -591,42 +591,39 @@ message WorkflowExecutionOptions {
591591
// and possibly other features added in the future.
592592
// User timers are not classified as in-flight work and will be skipped over.
593593
// When time advances, it skips to the earlier of the next user timer or the configured bound, if either exists.
594+
//
595+
// Propagation behavior of time skipping:
596+
// The enabled flag, bound fields, and accumulated skipped duration are propagated to related executions as follows:
597+
// (1) Child workflows and continue-as-new: both the configuration and the accumulated skipped duration are
598+
// inherited from the current execution. The configured bound is shared between the inherited skipped
599+
// duration and any additional duration skipped by the new run.
600+
// (2) Retry and cron: the configuration and accumulated skipped duration are inherited as recorded when the
601+
// current workflow started; the accumulated skipped duration of the current run is not propagated.
602+
// (3) Reset: the new run retains the time-skipping configuration of the current execution. Because reset replays
603+
// all events up to the reset point and re-applies any UpdateWorkflowExecutionOptions changes made after that
604+
// point, the resulting run ends up with the same final time-skipping configuration as the previous run.
594605
message TimeSkippingConfig {
606+
reserved 2, 6;
607+
reserved "disable_propagation", "max_target_time";
595608

596609
// Enables or disables time skipping for this workflow execution.
597-
// By default, this field is propagated to transitively related workflows (child workflows/start-as-new/reset)
598-
// at the time they are started.
599-
// Changes made after a transitively related workflow has started are not propagated.
600610
bool enabled = 1;
601611

602-
// If set, the enabled field is not propagated to transitively related workflows.
603-
bool disable_propagation = 2;
604-
605-
// Optional bound that limits how long time skipping remains active.
606-
// Once the bound is reached, time skipping is automatically disabled.
607-
// It can later be re-enabled via UpdateWorkflowExecutionOptions.
608-
//
609-
// This is particularly useful in testing scenarios where workflows
610-
// are expected to receive signals, updates, or other events while
611-
// timers are in progress.
612+
// Optional bound that limits the gap between the virtual time of this execution and wall-clock time.
613+
// Once the bound is reached, time skipping is automatically disabled,
614+
// but can be re-enabled by setting `enabled` to true via UpdateWorkflowExecutionOptions.
615+
// This bound cannot be set to a value smaller than the execution's currently skipped duration.
612616
//
613-
// This bound is not propagated to transitively related workflows.
614-
// When bound is also needed for transitively related workflows,
615-
// it is recommended to set disable_propagation to true
616-
// and configure TimeSkippingConfig explicitly for transitively related workflows.
617+
// This is useful in testing scenarios where a workflow is expected to receive
618+
// signals, updates, or other external events while timers are in progress.
617619
oneof bound {
618-
619620
// Maximum total virtual time that can be skipped.
620621
google.protobuf.Duration max_skipped_duration = 4;
621622

622623
// Maximum elapsed time since time skipping was enabled.
623624
// This includes both skipped time and real time elapsing.
624625
// (-- api-linter: core::0142::time-field-names=disabled --)
625626
google.protobuf.Duration max_elapsed_duration = 5;
626-
627-
// Absolute virtual timestamp at which time skipping is disabled.
628-
// Time skipping will not advance beyond this point.
629-
google.protobuf.Timestamp max_target_time = 6;
630627
}
631628
}
632629

temporal/api/workflowservice/v1/request_response.proto

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,7 @@ message StartWorkflowExecutionRequest {
199199
temporal.api.common.v1.Priority priority = 27;
200200
// Deployment Options of the worker who will process the eager task. Passed when `request_eager_execution=true`.
201201
temporal.api.deployment.v1.WorkerDeploymentOptions eager_worker_deployment_options = 28;
202+
202203
// Time-skipping configuration. If not set, time skipping is disabled.
203204
temporal.api.workflow.v1.TimeSkippingConfig time_skipping_config = 29;
204205
}

0 commit comments

Comments
 (0)