Skip to main content
Temporal Ruby SDK

Test and run a Worker

~10 minutesTemporal beginnerHands-on tutorial
  1. Build the application
  2. Test and run a Worker
  3. Run and observe retries

Now that the Workflow and Activities are in place, you'll configure a Worker to host them and write tests to verify they behave as expected. The Worker polls a Task Queue and runs your code when work arrives.

Define the Task Queue name

When you start a Temporal Workflow, the Workflow and its Activities get scheduled on the Temporal Service's Task Queue. A Worker hosts Workflow and Activity functions and polls the Task Queue for tasks related to those Workflows and Activities. After the Worker runs the code, it communicates the results back to the Temporal Service where they're stored in the Event History.

In your Worker program, you need to specify the name of the Task Queue, which must match the Task Queue name used whenever you interact with a Workflow from a client application. The Task Queue name is a case-insensitive string - define it as a constant so you can reuse it.

Create the file ip_geolocate.rb within your lib folder:

touch lib/ip_geolocate.rb

This file declares the IPGeolocate module, requires all children of the IPGeolocate module, and also defines the TASK_QUEUE_NAME. Open the file and add the following lines to the file to define the constant for the Task Queue:

lib/ip_geolocate.rb
# Load Bundler and load all your gems
require_relative "ip_geolocate/get_ip_activity"
require_relative "ip_geolocate/get_location_activity"
require_relative "ip_geolocate/get_address_from_ip_workflow"

module IPGeolocate
TASK_QUEUE_NAME = "ip-address-ruby"
end

Configure and run a Worker

Now you can create the Worker program. Create the file worker.rb in the lib directory:

touch lib/worker.rb

Then open worker.rb in your editor and add the following code to define the Worker program:

lib/worker.rb
require_relative 'ip_geolocate'
require 'temporalio/client'
require 'temporalio/worker'

# Create a client
begin
client = Temporalio::Client.connect('localhost:7233', 'default')
rescue StandardError => e
puts e.message
exit 1
end

# Create a worker with the client, activities, and workflows
worker = Temporalio::Worker.new(
client:,
task_queue: IPGeolocate::TASK_QUEUE_NAME,
workflows: [IPGeolocate::GetAddressFromIPWorkflow],
activities: [IPGeolocate::GetIPActivity, IPGeolocate::GetLocationActivity]
)

# Run the worker until SIGINT. This can be done in many ways, see "Workers" section for details.
worker.run(shutdown_signals: ['SIGINT'])

The code requires the ip_geolocate module, which includes your Workflow and Activity Definitions. It also uses the TASK_QUEUE_NAME constant.

You first create a client, and then you create a Worker that uses the client, along with the Task Queue it should listen on. By default, the client connects to the Temporal Service running at localhost on port 7233, and connects to the default namespace. You can change this by setting values in the Client Options.

In this case your Worker will run your Workflow and your two Activities, but there are cases where you could configure one Worker to run Activities, and another Worker to run the Workflows.

Now you'll start the Worker. Be sure you have started the local Temporal Service and execute the following command to start your Worker:

bundle exec ruby lib/worker.rb

Your Worker will then begin running and is polling the Temporal Service for Workflows to run, but before you start your Workflow, you'll write tests to prove it works as expected.

Write a Workflow test

The Temporal Ruby SDK includes methods that help you test your Workflow executions. Let's add a basic unit test to the application to make sure the Workflow works as expected.

You'll use the temporalio/testing package, which provides a WorkflowEnvironment that downloads and runs a lightweight test server.

Create a test directory:

mkdir test

Then create the file get_address_from_ip_workflow_test.rb within the test directory:

touch test/get_address_from_ip_workflow_test.rb

Add the following code to get_address_from_ip_workflow_test.rb to test the Workflow execution:

test/get_address_from_ip_workflow_test.rb
require 'test_helper'
require 'securerandom'
require 'temporalio/testing'
require 'temporalio/worker'
require 'ip_geolocate'

class GetAddressFromIPWorkflowTest < Minitest::Test
class MockGetIPActivity < Temporalio::Activity::Definition
activity_name :GetIPActivity

def execute
"1.1.1.1"
end
end

class MockGetLocationActivity < Temporalio::Activity::Definition
activity_name :GetLocationActivity

def execute(ip)
"Planet Earth"
end
end

def test_gets_location_from_ip_with_mocked_activities
Temporalio::Testing::WorkflowEnvironment.start_local do |env|
worker = Temporalio::Worker.new(
client: env.client,
task_queue: "test",
workflows: [IPGeolocate::GetAddressFromIPWorkflow],
activities: [MockGetIPActivity, MockGetLocationActivity],
workflow_executor: Temporalio::Worker::WorkflowExecutor::ThreadPool.default
)
worker.run do
result = env.client.execute_workflow(
IPGeolocate::GetAddressFromIPWorkflow,
"Testing",
id: "test-#{SecureRandom.uuid}",
task_queue: worker.task_queue
)
assert_equal 'Hello, Testing. Your IP is 1.1.1.1 and you are located in Planet Earth.', result
end
end
end
end

WorkflowEnvironment is a runtime environment used to test a Workflow. You use it to connect the Client and Worker to the test server and interact with the test server. You'll use this to register your Workflow Type and access information about the Workflow Execution, such as whether it completed successfully and the result or error it returned.

This test sets up a test environment to run Workflows that uses a lightweight Temporal Service specifically for testing. In the test itself, you create a Worker that connects to the test environment. This should look familiar, as it's similar to the code you wrote to define your Worker program.

Instead of using your actual Activities, you replace the Activities GetIPActivity and GetLocationActivity with methods that return hard-coded values. This way you're testing the Workflow's logic independently of the Activities. If you wanted to test the Activities directly as part of an integration test, you'd specify them directly as you did when you wrote the Worker program.

Run the test:

bundle exec ruby -Ilib:test test/get_address_from_ip_workflow_test.rb

The test environment starts, spins up a Worker, and executes the Workflow in the test environment. At the end, you'll see that your test passes:

Finished tests in 2.358264s, 0.4240 tests/s, 0.4240 assertions/s.
1 tests, 1 assertions, 0 failures, 0 errors, 0 skips

Write Activity tests

With a Workflow test in place, you can write unit tests for the Activities.

Both of your Activities make external calls to services that will change their results based on who runs them. It will be challenging to test these Activities reliably. For example, the IP address may vary based on your machine's location.

To ensure you can test the Activities in isolation, you'll stub out the HTTP calls. The ActivityEnvironment from the temporalio/testing package lets you test Activities as if they were part of a Temporal Application.

Create the file get_ip_activity_test.rb:

touch test/get_ip_activity_test.rb

Next, write the test for the GetIPActivity Activity:

test/get_ip_activity_test.rb
require 'test_helper'
require 'securerandom'
require 'temporalio/testing'
require 'ip_geolocate/get_ip_activity'

class GetIPActivityTest < Minitest::Test
def test_gets_ip
env = Temporalio::Testing::ActivityEnvironment.new

Net::HTTP.stub(:get, ->(*) { "1.1.1.1" }) do
result = env.run(IPGeolocate::GetIPActivity)
assert_equal "1.1.1.1", result
end
end

end

Now, create a test file for get_location_activity_test.rb:

touch test/get_location_activity_test.rb

Next, write the test for the GetLocationActivity Activity, using Net::HTTP to stub out actual HTTP calls so your tests are consistent:

test/get_location_activity_test.rb
require "test_helper"
require 'securerandom'
require 'temporalio/testing'
require "ip_geolocate/get_location_activity"

class GetLocationActivityTest < Minitest::Test
def test_gets_ip
env = Temporalio::Testing::ActivityEnvironment.new

fake_location = {
city: 'Sample City',
regionName: 'Sample Region',
country: 'Sample Country'
}.to_json;

Net::HTTP.stub(:get, ->(*) { fake_location }) do
result = env.run(IPGeolocate::GetLocationActivity, "1.1.1.1")
assert_equal "Sample City, Sample Region, Sample Country", result
end
end

end

To test the Activity itself, you use the test environment to execute the Activity rather than directly calling the GetLocationActivity method. You get the result from the Activity Execution and then ensure it matches the value you expect.

This test looks similar to the previous one; you mock out the HTTP client and ensure it returns the expected data, and then you execute the Activity in the test environment. Then you retrieve the value and ensure it's what you expect.

Run the tests to see them pass:

bundle exec ruby -Ilib:test test/get_ip_activity_test.rb
bundle exec ruby -Ilib:test test/get_location_activity_test.rb
Finished tests in 0.000718s, 1392.7570 tests/s, 1392.7570 assertions/s.
1 tests, 1 assertions, 0 failures, 0 errors, 0 skips

Now that you have your tests passing, it's time to start a Workflow Execution and observe how Temporal handles failures.

Get notified when we launch new educational content

New courses, tutorials, and learning resources - straight to your inbox.

Subscribe
Feedback