Repository navigation
Description
Problem: Testing Temporal Workflows with Signals in Ruby SDK Time-Skipping Environment
Context
I'm testing a workflow in the Temporalio Ruby SDK that uses wait_condition to wait for signals. The workflow works correctly in production, but I cannot test the signal-driven continuation in the time-skipping test environment (Temporalio::Testing::WorkflowEnvironment.start_time_skipping).
Workflow Pattern (Simplified)
class PipelineExecutionWorkflow < Temporalio::Workflow
workflow_signal
def customer_replied
@customer_replied = true
end
def execute(opportunity_id, pipeline_id)
# Step 1: Send initial email
send_email_activity(opportunity_id)
# Step 2: Wait for customer reply signal
Temporalio::Workflow.timeout(48.hours) do
Temporalio::Workflow.wait_condition { @customer_replied }
end
# Step 3: Process customer reply (extract data, send AI response)
if @customer_replied
extract_and_respond(opportunity_id)
end
{ "success" => true }
end
endWhat I've Tried in Tests
Temporalio::Testing::WorkflowEnvironment.start_time_skipping do |env|
worker = Temporalio::Worker.new(
client: env.client,
task_queue: "test-queue",
workflows: [PipelineExecutionWorkflow],
activities: [SendEmailActivity, ExtractActivity]
)
worker.run do
# Start workflow (doesn't wait for completion)
workflow_handle = env.client.start_workflow(
PipelineExecutionWorkflow,
opportunity_id,
pipeline_id,
id: "test-pipeline-#{opportunity_id}",
task_queue: "test-queue"
)
# Give time for initial email to be sent
sleep 0.5
# Check workflow state - shows it's waiting
state = workflow_handle.query("get_state")
# => {"waiting_for_signal" => true, "customer_replied" => false}
# Send the signal
workflow_handle.signal("customer_replied")
# Check state again - signal was received!
state_after = workflow_handle.query("get_state")
# => {"waiting_for_signal" => false, "customer_replied" => true}
# But when I try to get the result, it times out or returns nil
result = workflow_handle.result # ← TIMES OUT or returns nil
# The workflow doesn't continue executing after receiving the signal
end
endObserved Behavior
- ✅ Workflow starts successfully
- ✅ Initial email activity executes
- ✅ Workflow enters wait state (
wait_condition) - ✅ Signal is received (verified via query -
@customer_repliedbecomestrue) - ❌ Workflow doesn't continue execution after signal received
- ❌
workflow_handle.resulttimes out or workflow appears "stuck"
Questions
With the Temporal Ruby SDK source code available:
-
Is this a known limitation of the time-skipping test environment with
wait_conditionand signals? -
What is the correct way to test workflows that use
wait_conditionwith signals in the time-skipping environment? -
Should I use a different testing approach for signal-driven workflows? (e.g., real Temporal server, different test helper methods)
-
Is there a way to manually advance time or "wake up" the workflow after sending a signal in the test environment?
-
Are there any special considerations or setup required for testing signal-driven workflows that use
wait_condition?
Additional Context
- Ruby SDK version: 1.0.0 (from Gemfile)
- The workflow works perfectly in production with real Temporal server
- Synchronous workflows (without signals/wait) test fine in time-skipping environment
- I've tried both
start_workflow(non-blocking) andexecute_workflow(blocking) - neither works for the signal continuation
Activity
[-][Feature Request] FILL_TITLE_HERE[/-][+]Problem: Testing Temporal Workflows with Signals in Ruby SDK Time-Skipping Environment[/+]cretz commentedon Nov 10, 2025
Mentioned at https://github.com/temporalio/sdk-ruby?tab=readme-ov-file#workflow-testing (though maybe not clearly enough), the automatic time-skipping doesn't kick in until you wait for the workflow result. So the workflow does not progress automatically until you wait for the result (and no activities are running). But you can make it progress manually by calling
sleepon the environment.I'd be curious to see what this looks like as the latter should progress automatically assuming the activity runs as expected (i.e. one with its name is registered). Usually you'd have to run
execute_workflowin a background thread and you wouldn't get the handle to even make those signal calls on (so if the activity is registered, a 48h timeout would occur immediately based on the code).(also feel free to join us on
#ruby-sdkchannel on Slack if easier to chat about time-skipping test environments and other Ruby things)