diff --git a/CHANGELOG.md b/CHANGELOG.md index e0ad92e3..d7aa2cc7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,19 @@ to docs, or any other relevant information. ## [Unreleased] +### Added + +- Exposed `Temporalio::Workflow::ContinueAsNewError#backoff_start_interval`, to allow the new workflow to start after a delay. + +### Fixed + +#### `Workflow.suggest_continue_as_new_reasons` returns workflow enum values + +Workflow activations containing continue-as-new suggestion reasons previously failed because the worker tried to call `to_i` on bridge enum symbols. Continue-as-new suggestion reasons are now converted from bridge enum symbols to +`Temporalio::SuggestContinueAsNewReason` integer enum values before being exposed to workflows. + +## [v1.5.0] - 2026-06-11 + ### Breaking Changes #### `Activity::Info` workflow fields are now nullable @@ -35,8 +48,6 @@ Existing workflow-only code paths are unaffected at runtime. The recommended mig ### Added -- Exposed `Temporalio::Workflow::ContinueAsNewError#backoff_start_interval`, to allow the new workflow to start after a delay. - #### Standalone Activities Activities can now be started directly from a client, independently of any workflow. `Client#start_activity` @@ -65,19 +76,4 @@ correctly receives `Temporalio::Error::WorkflowUpdateFailedError`. (#454) but defers dispatch to a worker until the delay elapses. Retry attempts do not re-apply the delay. `ScheduleToStart` and `ScheduleToClose` timeout clocks begin counting after the delay elapses; `StartToClose` and `Heartbeat` are unaffected. Currently experimental. - diff --git a/temporalio/lib/temporalio/internal/worker/workflow_instance.rb b/temporalio/lib/temporalio/internal/worker/workflow_instance.rb index f5036680..970154ce 100644 --- a/temporalio/lib/temporalio/internal/worker/workflow_instance.rb +++ b/temporalio/lib/temporalio/internal/worker/workflow_instance.rb @@ -180,7 +180,9 @@ def activate(activation) @commands = [] @current_activation_error = nil @continue_as_new_suggested = activation.continue_as_new_suggested - @suggest_continue_as_new_reasons = activation.suggest_continue_as_new_reasons.map(&:to_i) + @suggest_continue_as_new_reasons = activation.suggest_continue_as_new_reasons.map do |reason| + ProtoUtils.enum_to_int(Api::Enums::V1::SuggestContinueAsNewReason, reason) + end @target_worker_deployment_version_changed = activation.target_worker_deployment_version_changed @current_deployment_version = WorkerDeploymentVersion._from_bridge( activation.deployment_version_for_current_task diff --git a/temporalio/test/worker/workflow_instance_test.rb b/temporalio/test/worker/workflow_instance_test.rb new file mode 100644 index 00000000..5a01bed6 --- /dev/null +++ b/temporalio/test/worker/workflow_instance_test.rb @@ -0,0 +1,88 @@ +# frozen_string_literal: true + +require 'logger' +require 'temporalio/converters' +require 'temporalio/internal/bridge/api' +require 'temporalio/internal/worker/workflow_instance' +require 'temporalio/runtime' +require 'temporalio/workflow' +require 'test' + +module Worker + class WorkflowInstanceTest < Test + class ContinueAsNewSuggestionWorkflow < Temporalio::Workflow::Definition + def execute + [ + Temporalio::Workflow.continue_as_new_suggested, + Temporalio::Workflow.suggest_continue_as_new_reasons + ] + end + end + + def test_continue_as_new_suggestion_reasons_are_visible_as_workflow_enum_ints + data_converter = Temporalio::Converters::DataConverter.default + initial_activation = Temporalio::Internal::Bridge::Api::WorkflowActivation::WorkflowActivation.new( + run_id: 'run-id', + timestamp: Google::Protobuf::Timestamp.new(seconds: Time.now.to_i), + history_length: 1, + history_size_bytes: 1, + jobs: [ + Temporalio::Internal::Bridge::Api::WorkflowActivation::WorkflowActivationJob.new( + initialize_workflow: Temporalio::Internal::Bridge::Api::WorkflowActivation::InitializeWorkflow.new( + workflow_type: 'ContinueAsNewSuggestionWorkflow', + workflow_id: 'workflow-id', + randomness_seed: 1, + start_time: Google::Protobuf::Timestamp.new(seconds: Time.now.to_i), + workflow_task_timeout: Google::Protobuf::Duration.new(seconds: 10) + ) + ) + ] + ) + + instance = Temporalio::Internal::Worker::WorkflowInstance.new( + Temporalio::Internal::Worker::WorkflowInstance::Details.new( + namespace: 'namespace', + task_queue: 'task-queue', + definition: Temporalio::Workflow::Definition::Info.from_class(ContinueAsNewSuggestionWorkflow), + initial_activation:, + logger: Logger.new(nil), + metric_meter: Temporalio::Runtime.default.metric_meter, + payload_converter: data_converter.payload_converter, + failure_converter: data_converter.failure_converter, + interceptors: [], + disable_eager_activity_execution: false, + illegal_calls: nil, + workflow_failure_exception_types: [], + unsafe_workflow_io_enabled: false, + assert_valid_local_activity: ->(_) {} + ) + ) + + completion = instance.activate( + Temporalio::Internal::Bridge::Api::WorkflowActivation::WorkflowActivation.new( + run_id: 'run-id', + timestamp: Google::Protobuf::Timestamp.new(seconds: Time.now.to_i), + history_length: 1, + history_size_bytes: 1, + continue_as_new_suggested: true, + suggest_continue_as_new_reasons: [ + Temporalio::Api::Enums::V1::SuggestContinueAsNewReason:: + SUGGEST_CONTINUE_AS_NEW_REASON_HISTORY_SIZE_TOO_LARGE, + Temporalio::Api::Enums::V1::SuggestContinueAsNewReason:: + SUGGEST_CONTINUE_AS_NEW_REASON_TOO_MANY_HISTORY_EVENTS + ] + ) + ) + command = completion.successful.commands.fetch(0) + result = data_converter.payload_converter.from_payload(command.complete_workflow_execution.result) + + assert_equal [ + true, + [ + Temporalio::SuggestContinueAsNewReason::HISTORY_SIZE_TOO_LARGE, + Temporalio::SuggestContinueAsNewReason::TOO_MANY_HISTORY_EVENTS + ] + ], result + end + end +end diff --git a/temporalio/test/worker_workflow_test.rb b/temporalio/test/worker_workflow_test.rb index 66beef49..dc07f53d 100644 --- a/temporalio/test/worker_workflow_test.rb +++ b/temporalio/test/worker_workflow_test.rb @@ -240,16 +240,20 @@ def execute [ Temporalio::Workflow.continue_as_new_suggested, Temporalio::Workflow.current_history_length, - Temporalio::Workflow.current_history_size + Temporalio::Workflow.current_history_size, + Temporalio::Workflow.suggest_continue_as_new_reasons ] end end def test_history_info - can_suggested, hist_len, hist_size = execute_workflow(HistoryInfoWorkflow) #: [bool, Integer, Integer] + can_suggested, hist_len, hist_size, reasons = + execute_workflow(HistoryInfoWorkflow) #: [bool, Integer, Integer, Array[Integer]] refute can_suggested assert hist_len > 60 assert hist_size > 1500 + assert_instance_of Array, reasons + assert_empty reasons end class WaitConditionWorkflow < Temporalio::Workflow::Definition