diff --git a/Sources/Temporal/API/SuggestContinueAsNewReason.swift b/Sources/Temporal/API/SuggestContinueAsNewReason.swift new file mode 100644 index 0000000..b81522c --- /dev/null +++ b/Sources/Temporal/API/SuggestContinueAsNewReason.swift @@ -0,0 +1,34 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift Temporal SDK open source project +// +// Copyright (c) 2026 Apple Inc. and the Swift Temporal SDK project authors +// Licensed under MIT License +// +// See LICENSE.txt for license information +// See CONTRIBUTORS.txt for the list of Swift Temporal SDK project authors +// +// SPDX-License-Identifier: MIT +// +//===----------------------------------------------------------------------===// + +/// Specifies why the server suggests a workflow should continue-as-new. +/// +/// When the server detects that a workflow's state is growing too large, +/// it provides one or more reasons to indicate why a continue-as-new is recommended. +/// +/// - Important: This is currently experimental and may be removed or changed in the future. +@nonexhaustive +public enum SuggestContinueAsNewReason: Sendable, Hashable { + /// Unspecified reason. + case unspecified + + /// The workflow history size in bytes is getting too large. + case historySizeTooLarge + + /// The workflow history event count is getting too large. + case tooManyHistoryEvents + + /// The workflow's count of completed plus in-flight updates is too large. + case tooManyUpdates +} diff --git a/Sources/Temporal/Extensions/SuggestContinueAsNewReason+Proto.swift b/Sources/Temporal/Extensions/SuggestContinueAsNewReason+Proto.swift new file mode 100644 index 0000000..959d117 --- /dev/null +++ b/Sources/Temporal/Extensions/SuggestContinueAsNewReason+Proto.swift @@ -0,0 +1,30 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift Temporal SDK open source project +// +// Copyright (c) 2026 Apple Inc. and the Swift Temporal SDK project authors +// Licensed under MIT License +// +// See LICENSE.txt for license information +// See CONTRIBUTORS.txt for the list of Swift Temporal SDK project authors +// +// SPDX-License-Identifier: MIT +// +//===----------------------------------------------------------------------===// + +extension SuggestContinueAsNewReason { + init(_ proto: Api.Enums.V1.SuggestContinueAsNewReason) { + switch proto { + case .unspecified: + self = .unspecified + case .historySizeTooLarge: + self = .historySizeTooLarge + case .tooManyHistoryEvents: + self = .tooManyHistoryEvents + case .tooManyUpdates: + self = .tooManyUpdates + case .UNRECOGNIZED: + self = .unspecified + } + } +} diff --git a/Sources/Temporal/Worker/Workflow/InternalWorkflowContext.swift b/Sources/Temporal/Worker/Workflow/InternalWorkflowContext.swift index c5485b6..763b845 100644 --- a/Sources/Temporal/Worker/Workflow/InternalWorkflowContext.swift +++ b/Sources/Temporal/Worker/Workflow/InternalWorkflowContext.swift @@ -97,6 +97,11 @@ struct InternalWorkflowContext: Sendable { self.stateMachine.continueAsNewSuggested() } + /// The reasons why continue as new was suggested. + var suggestContinueAsNewReasons: [SuggestContinueAsNewReason] { + self.stateMachine.suggestContinueAsNewReasons() + } + /// Current number of events in the history. var currentHistoryLength: Int { self.stateMachine.currentHistoryLength() diff --git a/Sources/Temporal/Worker/Workflow/WorkflowContext.swift b/Sources/Temporal/Worker/Workflow/WorkflowContext.swift index 7b3a164..5419d29 100644 --- a/Sources/Temporal/Worker/Workflow/WorkflowContext.swift +++ b/Sources/Temporal/Worker/Workflow/WorkflowContext.swift @@ -216,6 +216,17 @@ public struct WorkflowContext: @unchecked Sendable self.internalContext.continueAsNewSuggested } + /// The reasons why continue-as-new is suggested. + /// + /// When the server detects that a workflow's state is growing too large, + /// it provides one or more reasons indicating why a continue-as-new is recommended. + /// This array is empty when ``continueAsNewSuggested`` is `false`. + /// + /// - Important: This is currently experimental and may be removed or changed in the future. + public var suggestContinueAsNewReasons: [SuggestContinueAsNewReason] { + self.internalContext.suggestContinueAsNewReasons + } + /// Current number of events in the history. public var currentHistoryLength: Int { self.internalContext.currentHistoryLength diff --git a/Sources/Temporal/Worker/Workflow/WorkflowContextView.swift b/Sources/Temporal/Worker/Workflow/WorkflowContextView.swift index a6509c2..debe05c 100644 --- a/Sources/Temporal/Worker/Workflow/WorkflowContextView.swift +++ b/Sources/Temporal/Worker/Workflow/WorkflowContextView.swift @@ -76,6 +76,17 @@ public struct WorkflowContextView: @unchecked Sendable { storage.continueAsNewSuggested() } + /// The reasons why continue-as-new is suggested. + /// + /// When the server detects that a workflow's state is growing too large, + /// it provides one or more reasons indicating why a continue-as-new is recommended. + /// This array is empty when ``continueAsNewSuggested`` is `false`. + /// + /// - Important: This is currently experimental and may be removed or changed in the future. + public var suggestContinueAsNewReasons: [SuggestContinueAsNewReason] { + storage.suggestContinueAsNewReasons() + } + /// Current number of events in the history. public var currentHistoryLength: Int { storage.currentHistoryLength() diff --git a/Sources/Temporal/Worker/Workflow/WorkflowStateMachine.swift b/Sources/Temporal/Worker/Workflow/WorkflowStateMachine.swift index 38d281c..4d2ccac 100644 --- a/Sources/Temporal/Worker/Workflow/WorkflowStateMachine.swift +++ b/Sources/Temporal/Worker/Workflow/WorkflowStateMachine.swift @@ -75,6 +75,9 @@ struct WorkflowStateMachine: ~Copyable { /// Whether continue as new was suggested. var continueAsNewSuggested: Bool + /// The reasons why continue as new was suggested. + var suggestContinueAsNewReasons: [SuggestContinueAsNewReason] + /// Current number of events in the history. var currentHistoryLength: Int @@ -158,6 +161,7 @@ struct WorkflowStateMachine: ~Copyable { isReplaying: false, now: .now, continueAsNewSuggested: false, + suggestContinueAsNewReasons: [], currentHistoryLength: 0, currentHistorySize: 0, commands: [], @@ -268,6 +272,9 @@ struct WorkflowStateMachine: ~Copyable { active.isReplaying = activation.isReplaying active.now = activation.timestamp.date active.continueAsNewSuggested = activation.continueAsNewSuggested + active.suggestContinueAsNewReasons = activation.suggestContinueAsNewReasons.map { + SuggestContinueAsNewReason($0) + } active.currentHistoryLength = Int(activation.historyLength) active.currentHistorySize = Int(activation.historySizeBytes) if activation.hasDeploymentVersionForCurrentTask { @@ -950,6 +957,12 @@ struct WorkflowStateMachine: ~Copyable { } } + func suggestContinueAsNewReasons() -> [SuggestContinueAsNewReason] { + switch state { + case .active(let active): active.suggestContinueAsNewReasons + } + } + func currentHistorySize() -> Int { switch state { case .active(let active): active.currentHistorySize diff --git a/Sources/Temporal/Worker/Workflow/WorkflowStateMachineStorage.swift b/Sources/Temporal/Worker/Workflow/WorkflowStateMachineStorage.swift index d6e6753..ed727a5 100644 --- a/Sources/Temporal/Worker/Workflow/WorkflowStateMachineStorage.swift +++ b/Sources/Temporal/Worker/Workflow/WorkflowStateMachineStorage.swift @@ -547,6 +547,10 @@ package final class WorkflowStateMachineStorage: @unchecked Sendable { return self.stateMachine.continueAsNewSuggested() } + func suggestContinueAsNewReasons() -> [SuggestContinueAsNewReason] { + return self.stateMachine.suggestContinueAsNewReasons() + } + func currentHistorySize() -> Int { return self.stateMachine.currentHistorySize() }