Skip to content

Commit d3a2869

Browse files
committed
Config option for preserving no signals in the first task
1 parent 6e25a02 commit d3a2869

File tree

3 files changed

+59
-6
lines changed

3 files changed

+59
-6
lines changed

lib/temporal/configuration.rb

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ class Configuration
1818
attr_reader :timeouts, :error_handlers, :capabilities
1919
attr_accessor :connection_type, :converter, :use_error_serialization_v2, :host, :port, :credentials, :identity,
2020
:logger, :metrics_adapter, :namespace, :task_queue, :headers, :search_attributes, :header_propagators,
21-
:payload_codec, :legacy_signals
21+
:payload_codec, :legacy_signals, :no_signals_in_first_task
2222

2323
# See https://docs.temporal.io/blog/activity-timeouts/ for general docs.
2424
# We want an infinite execution timeout for cron schedules and other perpetual workflows.
@@ -92,6 +92,10 @@ def initialize
9292
# in Temporal server 1.20, it is ignored when connected to older versions and effectively
9393
# treated as true.
9494
@legacy_signals = false
95+
96+
# This is a legacy behavior that is incorrect, but which existing workflow code may rely on. Only
97+
# set to true until you can fix your workflow code.
98+
@no_signals_in_first_task = false
9599
end
96100

97101
def on_error(&block)

lib/temporal/workflow/state_manager.rb

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ def self.workflow_execution_started_event?(event)
138138

139139
private
140140

141-
attr_reader :dispatcher, :command_tracker, :marker_ids, :side_effects, :releases
141+
attr_reader :dispatcher, :command_tracker, :marker_ids, :side_effects, :releases, :config
142142

143143
def use_signals_first(raw_events)
144144
if sdk_flags.include?(SDKFlags::HANDLE_SIGNALS_FIRST)
@@ -149,14 +149,14 @@ def use_signals_first(raw_events)
149149
true
150150
elsif raw_events.any? { |event| StateManager.signal_event?(event) } &&
151151
# If this is being played for the first time, use the configuration flag to choose
152-
(!replay? && !@config.legacy_signals) &&
152+
(!replay? && !config.legacy_signals) &&
153153
# In order to preserve determinism, the server must support SDK metadata to order signals
154154
# first. This is checked last because it will result in a Temporal server call the first
155155
# time it's called in the worker process.
156-
@config.capabilities.sdk_metadata
156+
config.capabilities.sdk_metadata
157157
report_flag_used(SDKFlags::HANDLE_SIGNALS_FIRST)
158158

159-
if raw_events.any? { |event| StateManager.workflow_execution_started_event?(event) }
159+
if raw_events.any? { |event| StateManager.workflow_execution_started_event?(event) } && !config.no_signals_in_first_task
160160
report_flag_used(SDKFlags::SAVE_FIRST_TASK_SIGNALS)
161161
end
162162

spec/unit/lib/temporal/workflow/state_manager_spec.rb

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ class MyWorkflow < Temporal::Workflow; end
154154
state_manager.apply(history.next_window)
155155
end
156156
end
157-
157+
158158
context 'replaying with SAVE_FIRST_TASK_SIGNALS sdk flag' do
159159
let(:sdk_flags) do [
160160
Temporal::Workflow::SDKFlags::HANDLE_SIGNALS_FIRST,
@@ -385,6 +385,55 @@ def test_order(signal_first)
385385
end
386386
end
387387
end
388+
389+
context 'not replaying with a signal in the first workflow task' do
390+
let(:signal_entry) { Fabricate(:api_workflow_execution_signaled_event, event_id: 2) }
391+
let(:history) do
392+
Temporal::Workflow::History.new(
393+
[
394+
Fabricate(:api_workflow_execution_started_event, event_id: 1),
395+
signal_entry,
396+
Fabricate(:api_workflow_task_scheduled_event, event_id: 3)
397+
]
398+
)
399+
end
400+
401+
def test_order_one_task(*expected_sdk_flags)
402+
allow(connection).to receive(:get_system_info).and_return(system_info)
403+
signaled = false
404+
405+
dispatcher.register_handler(
406+
Temporal::Workflow::Signal.new(
407+
signal_entry.workflow_execution_signaled_event_attributes.signal_name
408+
),
409+
'signaled'
410+
) do
411+
signaled = true
412+
end
413+
414+
state_manager.apply(history.next_window)
415+
expect(state_manager.new_sdk_flags_used).to eq(Set.new(expected_sdk_flags))
416+
expect(signaled).to eq(true)
417+
end
418+
419+
context 'default config' do
420+
let(:config) { Temporal::Configuration.new }
421+
422+
it 'signal first' do
423+
test_order_one_task(
424+
Temporal::Workflow::SDKFlags::HANDLE_SIGNALS_FIRST,
425+
Temporal::Workflow::SDKFlags::SAVE_FIRST_TASK_SIGNALS
426+
)
427+
end
428+
end
429+
430+
context 'no signals in first task enabled' do
431+
let(:config) { Temporal::Configuration.new.tap { |c| c.no_signals_in_first_task = true } }
432+
it 'signal inline' do
433+
test_order_one_task(Temporal::Workflow::SDKFlags::HANDLE_SIGNALS_FIRST)
434+
end
435+
end
436+
end
388437
end
389438

390439
describe '#search_attributes' do

0 commit comments

Comments
 (0)