Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
c52d376
Add all Ruby SDK reference files (11 files, ~2100 lines)
donald-pinckney Mar 16, 2026
0dcac1e
Fix alignment issues in Ruby reference files
donald-pinckney Mar 16, 2026
dfcdc82
Fix correctness issues in Ruby reference files
donald-pinckney Mar 16, 2026
ef5d989
Add Ruby to all language references in SKILL.md and core files
donald-pinckney Mar 16, 2026
2e936b2
Merge branch 'main' into add-ruby-support
donald-pinckney May 26, 2026
f9c81ee
Apply suggestions from code review
donald-pinckney May 26, 2026
c3181b8
Apply suggestions from code review
donald-pinckney May 26, 2026
5312401
Apply suggestion from @chris-olszewski
donald-pinckney May 26, 2026
734a347
copy over sample code
donald-pinckney May 26, 2026
ce0d434
Remove useless section, mention Mutex
donald-pinckney May 27, 2026
d051bf3
cleanup mutex mentions
donald-pinckney May 27, 2026
b22eb20
Clean up transitive NDE section
donald-pinckney May 28, 2026
b0630d7
Menial changes to align to python structure
donald-pinckney May 28, 2026
afc00ef
Add Workflow Init section to Ruby advanced-features
donald-pinckney May 28, 2026
d3b0c3c
Document graceful_shutdown_period in Ruby Worker Tuning
donald-pinckney May 28, 2026
76a4f02
Propagate cancellation in Ruby activity-error handling
donald-pinckney May 28, 2026
41c6f0e
Align Ruby Workflow Failure section to Python
donald-pinckney May 28, 2026
adcb0d4
Add logger configuration to Ruby observability
donald-pinckney May 28, 2026
1269e03
Make Ruby Saga compensations cancellation-proof
donald-pinckney May 28, 2026
b08606a
Document patched() memoization caveat in Ruby versioning
donald-pinckney May 28, 2026
d0d5f4b
Add default versioning behavior to Ruby worker versioning
donald-pinckney May 28, 2026
649d296
Fix worker versioning config API names in Ruby docs
donald-pinckney May 28, 2026
dc1994b
Fix worker concurrency config in Ruby Worker Tuning
donald-pinckney May 28, 2026
5fe7a95
Align Ruby Workflow Init title with Python
donald-pinckney May 28, 2026
2c4004a
Structure Ruby Metrics to match Python
donald-pinckney May 28, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions SKILL.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
---
name: temporal-developer
description: This skill should be used when the user asks to "create a Temporal workflow", "write a Temporal activity", "debug stuck workflow", "fix non-determinism error", "Temporal Python", "Temporal TypeScript", "workflow replay", "activity timeout", "signal workflow", "query workflow", "worker not starting", "activity keeps retrying", "Temporal heartbeat", "continue-as-new", "child workflow", "saga pattern", "workflow versioning", "durable execution", "reliable distributed systems", or mentions Temporal SDK development.
description: This skill should be used when the user asks to "create a Temporal workflow", "write a Temporal activity", "debug stuck workflow", "fix non-determinism error", "Temporal Python", "Temporal TypeScript", "Temporal Ruby", "workflow replay", "activity timeout", "signal workflow", "query workflow", "worker not starting", "activity keeps retrying", "Temporal heartbeat", "continue-as-new", "child workflow", "saga pattern", "workflow versioning", "durable execution", "reliable distributed systems", or mentions Temporal SDK development.
version: 1.0.0
---

# Skill: temporal-developer

## Overview

Temporal is a durable execution platform that makes workflows survive failures automatically. This skill provides guidance for building Temporal applications in Python and TypeScript.
Temporal is a durable execution platform that makes workflows survive failures automatically. This skill provides guidance for building Temporal applications in Python, TypeScript, and Ruby.

## Core Architecture

Expand Down Expand Up @@ -92,6 +92,7 @@ Once you've downloaded the file, extract the downloaded archive and add the temp
1. First, read the getting started guide for the language you are working in:
- Python -> read `references/python/python.md`
- TypeScript -> read `references/typescript/typescript.md`
- Ruby -> read `references/ruby/ruby.md`
2. Second, read appropriate `core` and language-specific references for the task at hand.


Expand Down
1 change: 1 addition & 0 deletions references/core/determinism.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ Each Temporal SDK language provides a protection mechanism to make it easier to

- Python: The Python SDK runs workflows in a sandbox that intercepts and aborts non-deterministic calls at runtime.
- TypeScript: The TypeScript SDK runs workflows in an isolated V8 sandbox, intercepting many common sources of non-determinism and replacing them automatically with deterministic variants.
- Ruby: The Ruby SDK uses Illegal Call Tracing (via `TracePoint`) to detect forbidden method calls at runtime on the workflow fiber, combined with a Durable Fiber Scheduler that makes fiber operations deterministic.


## Detecting Non-Determinism
Expand Down
191 changes: 191 additions & 0 deletions references/ruby/advanced-features.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
# Ruby SDK Advanced Features

## Schedules

Create recurring workflow executions with `Temporalio::Client::Schedule`.

```ruby
require 'temporalio/client'

# Create a schedule
schedule_id = 'daily-report'
client.create_schedule(
schedule_id,
Temporalio::Client::Schedule.new(
action: Temporalio::Client::Schedule::Action::StartWorkflow.new(
DailyReportWorkflow,
id: 'daily-report',
task_queue: 'reports'
),
spec: Temporalio::Client::Schedule::Spec.new(
intervals: [
Temporalio::Client::Schedule::Spec::Interval.new(every: 86_400) # 1 day in seconds
]
)
)
)

# Manage schedules
handle = client.schedule_handle(schedule_id)
handle.pause(note: 'Maintenance window')
handle.unpause
handle.trigger
handle.delete
```

## Async Activity Completion

For activities that complete asynchronously (e.g., human tasks, external callbacks).

```ruby
class RequestApproval < Temporalio::Activity::Definition
def execute(request_id)
# Get task token for async completion
task_token = Temporalio::Activity::Context.current.info.task_token

# Store task token for later completion (e.g., in database)
store_task_token(request_id, task_token)

# Signal that this activity completes asynchronously
Temporalio::Activity::Context.current.raise_complete_async
end
end

# Later, complete the activity from another process
client = Temporalio::Client.connect('localhost:7233')
task_token = get_task_token(request_id)
handle = client.async_activity_handle(task_token: task_token)

if approved
handle.complete('approved')
else
handle.fail(Temporalio::Error::ApplicationError.new('Rejected'))
end
```

If you configure a `heartbeat_timeout:` on the activity, the external completer is responsible for sending heartbeats via the async handle. If you do NOT set a `heartbeat_timeout`, no heartbeats are required.

## Worker Tuning

Configure worker performance settings.

```ruby
worker = Temporalio::Worker.new(
client: client,
task_queue: 'my-queue',
workflows: [MyWorkflow],
activities: [MyActivity],
max_concurrent_workflow_tasks: 100,
max_concurrent_activities: 100
)
worker.run
```

## Workflow Failure Exception Types

Control which exceptions cause workflow failure vs workflow task failure (which Temporal retries automatically).

### Per-Workflow Configuration

```ruby
class MyWorkflow < Temporalio::Workflow::Definition
# Class method approach
def self.workflow_failure_exception_type
MyCustomError
end

def execute
raise MyCustomError, 'This fails the workflow, not just the task'
end
end
```

### Worker-Level Configuration

```ruby
Temporalio::Worker.new(
client: client,
task_queue: 'my-queue',
workflows: [MyWorkflow],
workflow_failure_exception_types: [MyCustomError]
)
```

**Tips:**
- Set to `[Exception]` in tests so any unhandled exception fails the workflow immediately rather than retrying the workflow task forever. Surfaces bugs faster.
- Include `Temporalio::Workflow::NondeterminismError` to fail the workflow instead of leaving it in a retrying state on non-determinism errors.

## Activity Concurrency and Executors

Ruby uses `Temporalio::Worker::ActivityExecutor::ThreadPool` by default. Activities run in a thread pool.

```ruby
# Default: activities run in thread pool
worker = Temporalio::Worker.new(
client: client,
task_queue: 'my-queue',
workflows: [MyWorkflow],
activities: [MyActivity],
activity_executors: {
default: Temporalio::Worker::ActivityExecutor::ThreadPool.new(max_threads: 20)
}
)
```

Fiber-based execution is also possible for IO-bound activities using Ruby's fiber scheduler.

## Rails Integration

### ActiveRecord Considerations

Never pass ActiveRecord models directly to Temporal workflows or activities. Serialize to plain data structures.

```ruby
# BAD - Passing AR model
client.execute_workflow(
ProcessOrderWorkflow,
Order.find(42), # Don't pass AR objects!
id: 'order-42',
task_queue: 'orders'
)

# GOOD - Pass serializable data
client.execute_workflow(
ProcessOrderWorkflow,
{ id: 42, total: order.total, status: order.status },
id: 'order-42',
task_queue: 'orders'
)
```

### Zeitwerk and Autoloading

Rails uses Zeitwerk for autoloading. Workflow and activity classes must be loadable by Zeitwerk or explicitly required.
Comment thread
donald-pinckney marked this conversation as resolved.
Outdated

```ruby
Comment thread
donald-pinckney marked this conversation as resolved.
# In config/initializers/temporal.rb or similar
# Eager load Temporal classes so they're available to the worker
Rails.application.config.after_initialize do
Dir[Rails.root.join('app/workflows/**/*.rb')].each { |f| require f }
Dir[Rails.root.join('app/activities/**/*.rb')].each { |f| require f }
end
Comment thread
donald-pinckney marked this conversation as resolved.
Outdated
```

### Forking Considerations

If using a forking server (Puma, Unicorn), workers must be created **after** the fork. Connections established before fork are not safe to share across processes.

```ruby
# In Puma config (puma.rb)
on_worker_boot do
Comment thread
donald-pinckney marked this conversation as resolved.
Outdated
# Create Temporal client and worker AFTER fork
client = Temporalio::Client.connect('localhost:7233')
worker = Temporalio::Worker.new(
client: client,
task_queue: 'my-queue',
workflows: [MyWorkflow],
activities: [MyActivity]
)
Thread.new { worker.run }
end
```
Loading