
Run your first Temporal application with the Ruby SDK
- Understand the application
- Run the application
- Simulate failures
In this tutorial, you'll run your first Temporal Application using the Ruby SDK. You'll use the Web UI for state visibility, then explore how Temporal helps you recover from common failures.
- Explore Temporal's core terminology and concepts.
- Run a Temporal Workflow Application using a Temporal Service and the Ruby SDK.
- Practice reviewing the state of the Workflow.
- Understand the inherent reliability of Workflow methods.
Prerequisites
- Set up a local development environment for developing Temporal Applications with Ruby
- Ensure you have Git installed to clone the project.
Application overview
The project simulates a money transfer application: withdrawals, deposits, and refunds. Money comes out of one account and goes into another. If the deposit fails after a successful withdrawal, the money returns to the original account via a compensating Refund Activity (a classic saga pattern).
Temporal automatically preserves application state when something fails - recovering processes where they left off or rolling them back.
Download the example application
The source code is available in a GitHub repository. Clone it:
git clone https://github.com/temporalio/money-transfer-project-template-ruby/
cd money-transfer-project-template-ruby
Workflow Definition
In the Ruby SDK, a Workflow Definition is a class that extends Temporalio::Workflow::Definition. The execute method is its entry point:
require_relative 'activities'
require_relative 'shared'
require 'temporalio/retry_policy'
require 'temporalio/workflow'
module MoneyTransfer
class MoneyTransferWorkflow < Temporalio::Workflow::Definition
def execute(details)
retry_policy = Temporalio::RetryPolicy.new(
max_interval: 10,
non_retryable_error_types: [
'InvalidAccountError',
'InsufficientFundsError'
]
)
Temporalio::Workflow.logger.info("Starting workflow (#{details})")
withdraw_result = Temporalio::Workflow.execute_activity(
BankActivities::Withdraw,
details,
start_to_close_timeout: 5,
retry_policy: retry_policy
)
begin
deposit_result = Temporalio::Workflow.execute_activity(
BankActivities::Deposit,
details,
start_to_close_timeout: 5,
retry_policy: retry_policy
)
"Transfer complete (transaction IDs: #{withdraw_result}, #{deposit_result})"
rescue Temporalio::Error::ActivityError => e
# Since the deposit failed, attempt to recover by refunding the withdrawal
refund_result = Temporalio::Workflow.execute_activity(
BankActivities::Refund,
details,
start_to_close_timeout: 5,
retry_policy: retry_policy
)
"Transfer complete (transaction IDs: #{withdraw_result}, #{refund_result})"
end
end
end
end
The Workflow's execute method is passed a TransferDetails struct:
TransferDetails = Struct.new(:source_account, :target_account, :amount, :reference_id) do
def to_s
"TransferDetails { #{source_account}, #{target_account}, #{amount}, #{reference_id} }"
end
end
The Retry Policy defined at the top of the Workflow limits the delay between retry attempts to 10 seconds and marks InvalidAccountError and InsufficientFundsError as non-retryable.
This tutorial doesn't handle every possible situation - including failure of the refund operation, which might involve a human-in-the-loop step.
Activity Definition
Activities derive from Temporalio::Activity::Definition and define an execute method. The Withdraw, Deposit, and Refund Activities each simulate calls to a banking service:
require_relative 'shared'
require 'temporalio/activity'
module MoneyTransfer
module BankActivities
class Withdraw < Temporalio::Activity::Definition
def execute(details)
puts("Doing a withdrawal from #{details.source_account} for #{details.amount}")
raise InsufficientFundsError, 'Transfer amount too large' if details.amount > 1000
# Uncomment to expose a bug and cause the Activity to fail
# x = details.amount / 0
"OKW-#{details.amount}-#{details.source_account}"
end
end
class Deposit < Temporalio::Activity::Definition
def execute(details)
puts("Doing a deposit into #{details.target_account} for #{details.amount}")
raise InvalidAccountError, 'Invalid account number' if details.target_account == 'B5555'
"OKD-#{details.amount}-#{details.target_account}"
end
end
class Refund < Temporalio::Activity::Definition
def execute(details)
puts("Refunding #{details.amount} back to account #{details.source_account}")
"OKR-#{details.amount}-#{details.source_account}"
end
end
end
end
The Withdraw Activity fails with InsufficientFundsError if the amount exceeds $1000 - a non-retryable error that fails the Workflow. The Deposit Activity fails with InvalidAccountError if the target is B5555, which is caught generically as Temporalio::Error::ActivityError and triggers a Refund.
Workflows have deterministic constraints - operations that interact with external systems go in Activities. Use Activities for business logic and Workflows to orchestrate them.
Get notified when we launch new educational content
New courses, tutorials, and learning resources - straight to your inbox.