Skip to main content
Temporal Ruby SDK

Run your first Temporal application with the Ruby SDK

~15 minutes totalTemporal beginnerHands-on tutorial
  1. Understand the application
  2. Run the application
  3. 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.

What you'll do
  • 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

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:

workflow.rb
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:

shared.rb
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 is a simplified example

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:

activities.rb
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.

Why you use Activities

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.

Subscribe
Feedback