Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 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: Develop, debug, and manage Temporal applications across Python, TypeScript, Go, Java and .NET. Use when the user is building workflows, activities, or workers with a Temporal SDK, debugging issues like non-determinism errors, stuck workflows, or activity retries, using Temporal CLI, Temporal Server, or Temporal Cloud, or working with durable execution concepts like signals, queries, heartbeats, versioning, continue-as-new, child workflows, or saga patterns.
description: Develop, debug, and manage Temporal applications across Python, TypeScript, Go, Java, .NET and Ruby. Use when the user is building workflows, activities, or workers with a Temporal SDK, debugging issues like non-determinism errors, stuck workflows, or activity retries, using Temporal CLI, Temporal Server, or Temporal Cloud, or working with durable execution concepts like signals, queries, heartbeats, versioning, continue-as-new, child workflows, or saga patterns.
version: 0.4.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, TypeScript, Go, Java and .NET.
Temporal is a durable execution platform that makes workflows survive failures automatically. This skill provides guidance for building Temporal applications in Python, TypeScript, Go, Java, .NET, and Ruby.

## Core Architecture

Expand Down Expand Up @@ -58,6 +58,7 @@ Check if `temporal` CLI is installed. If not, follow the instructions at `refere
- Go -> read `references/go/go.md`
- Java -> read `references/java/java.md`
- .NET (C#) -> read `references/dotnet/dotnet.md`
- Ruby -> read `references/ruby/ruby.md`
2. Second, read appropriate `core` and language-specific references for the task at hand.

## Primary References
Expand Down
1 change: 1 addition & 0 deletions references/core/determinism.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ Each Temporal SDK language provides a different level of protection against non-
- Java: The Java SDK has no sandbox. Determinism is enforced by developer conventions — the SDK provides `Workflow.*` APIs as safe alternatives (e.g., `Workflow.sleep()` instead of `Thread.sleep()`), and non-determinism is only detected at replay time via `NonDeterministicException`. A static analysis tool (`temporal-workflowcheck`, beta) can catch violations at build time. Cooperative threading under a global lock eliminates the need for synchronization.
- Go: The Go SDK has no runtime sandbox. Therefore, non-determinism bugs will never be immediately appararent, and are usually only observable during replay. The optional `workflowcheck` static analysis tool can be used to check for many sources of non-determinism at compile time.
- .NET: The .NET SDK has no sandbox. It uses a custom TaskScheduler and a runtime EventListener to detect invalid task scheduling. Developers must use `Workflow.*` safe alternatives (e.g., Workflow.DelayAsync instead of Task.Delay) and avoid non-deterministic .NET Task APIs.
- 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.

Regardless of which SDK you are using, it is your responsibility to ensure that workflow code does not contain sources of non-determinism. Use SDK-specific tools as well as replay tests for doing so.

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)
before_worker_boot do
# 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