Skip to content

Commit f26c364

Browse files
attempt to remove non-determism in type checking
1 parent 42cacf5 commit f26c364

2 files changed

Lines changed: 33 additions & 22 deletions

File tree

temporalio/test/support/sig_applicator.rb

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -43,18 +43,6 @@ module SigApplicator
4343
@mutex = Mutex.new
4444

4545
class << self
46-
# Known type mismatches that are not RBI issues. Internal terminal
47-
# interceptor implementations intentionally pass nil as next_interceptor,
48-
# and some tests intentionally pass wrong types to verify error handling.
49-
IGNORED_ERRORS = [
50-
# WorkerActivityTest passes a non-activity class to test validation
51-
# 'WorkerActivityTest::NotAnActivity',
52-
# implementation.rb:231 passes proto WorkflowType object instead of .name
53-
# 'Temporalio::Api::Common::V1::WorkflowType',
54-
# Proto conversion edge case returning inspect string
55-
# 'got type String with value "#<data Temporalio::RetryPo'
56-
].freeze
57-
5846
def apply_all!
5947
configure_error_handler!
6048
register_summary_hook!
@@ -79,15 +67,31 @@ def apply_all!
7967
end
8068

8169
def record_type_error(message)
82-
Temporalio::Workflow::Unsafe.illegal_call_tracing_disabled do
83-
@mutex.synchronize { @type_errors << message }
84-
end
70+
return if Thread.current[:sig_applicator_suppressed]
71+
72+
# Avoid illegal_call_tracing_disabled here — interacting with the
73+
# workflow tracer + mutex from inside error handlers can cause
74+
# non-deterministic behavior. Instead, rescue the NondeterminismError
75+
# that fires when accessing Mutex from within a workflow.
76+
@mutex.synchronize { @type_errors << message }
77+
rescue Temporalio::Workflow::NondeterminismError
78+
# Best-effort: append without synchronization when inside a workflow
79+
@type_errors << message
8580
end
8681

8782
def type_errors
8883
@mutex.synchronize { @type_errors.dup }
8984
end
9085

86+
# Suppress type error recording for the duration of a block.
87+
# Use for tests that intentionally pass wrong types.
88+
def suppress_errors
89+
Thread.current[:sig_applicator_suppressed] = true
90+
yield
91+
ensure
92+
Thread.current[:sig_applicator_suppressed] = false
93+
end
94+
9195
private
9296

9397
def configure_error_handler!
@@ -105,8 +109,6 @@ def configure_error_handler!
105109
return
106110
end
107111

108-
return if IGNORED_ERRORS.any? { |pattern| message.include?(pattern) }
109-
110112
# Include location for debugging
111113
location = opts[:location]
112114
full = location ? "#{message}\n Location: #{location}" : message

temporalio/test/worker_activity_test.rb

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -153,11 +153,20 @@ class NotAnActivity # rubocop:disable Lint/EmptyClass
153153

154154
def test_not_an_activity
155155
error = assert_raises(ArgumentError) do
156-
Temporalio::Worker.new(
157-
client: env.client,
158-
task_queue: "tq-#{SecureRandom.uuid}",
159-
activities: [NotAnActivity]
160-
)
156+
# Intentionally passing a non-activity class to test validation.
157+
# Suppress sorbet runtime errors since the wrong type is deliberate.
158+
block = proc do
159+
Temporalio::Worker.new(
160+
client: env.client,
161+
task_queue: "tq-#{SecureRandom.uuid}",
162+
activities: [NotAnActivity]
163+
)
164+
end
165+
if defined?(SigApplicator)
166+
SigApplicator.suppress_errors(&block)
167+
else
168+
block.call
169+
end
161170
end
162171
assert error.message.end_with?('does not extend Temporalio::Activity::Definition')
163172
end

0 commit comments

Comments
 (0)