Skip to content

Commit

Permalink
Demonstrate interoperability with Coinbase Ruby SDK
Browse files Browse the repository at this point in the history
  • Loading branch information
cretz committed Feb 4, 2025
1 parent ebaa2fa commit c440f5b
Show file tree
Hide file tree
Showing 10 changed files with 264 additions and 1 deletion.
7 changes: 6 additions & 1 deletion Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,12 @@

source 'https://rubygems.org'

gem 'temporalio'
# Primary Temporal dependency
gem 'temporalio', path: '../temporal-sdk-ruby/temporalio'

# Additional dependencies for certain samples
gem 'google-protobuf', '~> 3.25'
gem 'temporal-ruby', path: '../coinbase-temporal-ruby'

group :development do
gem 'minitest'
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ Prerequisites:
<!-- Keep this list in alphabetical order -->
* [activity_simple](activity_simple) - Simple workflow that calls two activities.
* [activity_worker](activity_worker) - Use Ruby activities from a workflow in another language.
* [coinbase_ruby](coinbase_ruby) - Demonstrate interoperability with the
[Coinbase Ruby SDK](https://github.com/coinbase/temporal-ruby).
* [context_propagation](context_propagation) - Use interceptors to propagate thread/fiber local data from clients
through workflows/activities.
* [message_passing_simple](message_passing_simple) - Simple workflow that accepts signals, queries, and updates.
Expand Down
24 changes: 24 additions & 0 deletions coinbase_ruby/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Coinbase Ruby

This sample shows a workflow, activity, and client from [Coinbase Ruby SDK](https://github.com/coinbase/temporal-ruby)
able to interoperate with a workflow, activity, and client from Temporal Ruby SDK. Specifically this sample contains an
activity in both SDKs, a workflow in both SDKs each calling both activities, a worker in both SDKs running in the same
process, and a starter with clients from each SDK each invoking both workflows.

To run, first see [README.md](../README.md) for prerequisites. Then, in another terminal, start the Ruby worker
from this directory:

bundle exec ruby worker.rb

Finally in another terminal, use the Ruby client to the workflow from this directory:

bundle exec ruby starter.rb

The Ruby code will invoke 4 workflows. The output of the final command should be:

```
Coinbase SDK workflow result from Temporal SDK client: ["Hello from Coinbase Ruby SDK, user1!", "Hello from Temporal Ruby SDK, user1!"]
Temporal SDK workflow result from Temporal SDK client: ["Hello from Coinbase Ruby SDK, user2!", "Hello from Temporal Ruby SDK, user2!"]
Coinbase SDK workflow result from Coinbase SDK client: ["Hello from Coinbase Ruby SDK, user3!", "Hello from Temporal Ruby SDK, user3!"]
Temporal SDK workflow result from Coinbase SDK client: ["Hello from Coinbase Ruby SDK, user4!", "Hello from Temporal Ruby SDK, user4!"]
```
9 changes: 9 additions & 0 deletions coinbase_ruby/coinbase_activity.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
require 'temporal-ruby'

module CoinbaseRuby
class CoinbaseActivity < Temporal::Activity
def execute(name)
"Hello from Coinbase Ruby SDK, #{name}!"
end
end
end
15 changes: 15 additions & 0 deletions coinbase_ruby/coinbase_workflow.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
require 'temporal-ruby'
require_relative 'coinbase_activity'

module CoinbaseRuby
class CoinbaseWorkflow < Temporal::Workflow
def execute(name)
[
# Execute activity on Coinbase SDK worker
CoinbaseActivity.execute!(name),
# Execute activity on Temporal SDK worker
workflow.execute_activity!(:TemporalActivity, name, options: { task_queue: 'coinbase-ruby-sample-temporal' })
]
end
end
end
56 changes: 56 additions & 0 deletions coinbase_ruby/starter.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# frozen_string_literal: true

# We must require Temporal SDK first and set the env var to prevent Coinbase SDK from trying to load its protos
require 'temporalio/client'
ENV['COINBASE_TEMPORAL_RUBY_DISABLE_PROTO_LOAD'] = '1'

require_relative 'coinbase_workflow'
require_relative 'temporal_workflow'
require 'logger'
require 'temporal-ruby'

# Create Temporal SDK client
client = Temporalio::Client.connect('localhost:7233', 'default')

# Run Coinbase workflow
result = client.execute_workflow(
CoinbaseRuby::CoinbaseWorkflow.name, 'user1',
id: 'coinbase-ruby-sample-workflow-id-1', task_queue: 'coinbase-ruby-sample-coinbase'
)
puts "Coinbase SDK workflow result from Temporal SDK client: #{result}"

# Run Temporal workflow
result = client.execute_workflow(
CoinbaseRuby::TemporalWorkflow, 'user2',
id: 'coinbase-ruby-sample-workflow-id-2', task_queue: 'coinbase-ruby-sample-temporal'
)
puts "Temporal SDK workflow result from Temporal SDK client: #{result}"

# Now do the same with Coinbase SDK, first configuring the client
Temporal.configure do |config|
config.host = 'localhost'
config.port = 7233
config.namespace = 'default'
end

# Run Coinbase workflow
run_id = Temporal.start_workflow(
CoinbaseRuby::CoinbaseWorkflow, 'user3',
options: { workflow_id: 'coinbase-ruby-sample-workflow-id-3', task_queue: 'coinbase-ruby-sample-coinbase' }
)
result = Temporal.await_workflow_result(
CoinbaseRuby::CoinbaseWorkflow,
workflow_id: 'coinbase-ruby-sample-workflow-id-3', run_id:
)
puts "Coinbase SDK workflow result from Coinbase SDK client: #{result}"

# Run Temporal workflow
run_id = Temporal.start_workflow(
:TemporalWorkflow, 'user4',
options: { workflow_id: 'coinbase-ruby-sample-workflow-id-4', task_queue: 'coinbase-ruby-sample-temporal' }
)
result = Temporal.await_workflow_result(
:TemporalWorkflow,
workflow_id: 'coinbase-ruby-sample-workflow-id-4', run_id:
)
puts "Temporal SDK workflow result from Coinbase SDK client: #{result}"
11 changes: 11 additions & 0 deletions coinbase_ruby/temporal_activity.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# frozen_string_literal: true

require 'temporalio/activity'

module CoinbaseRuby
class TemporalActivity < Temporalio::Activity::Definition
def execute(name)
"Hello from Temporal Ruby SDK, #{name}!"
end
end
end
19 changes: 19 additions & 0 deletions coinbase_ruby/temporal_workflow.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# frozen_string_literal: true

require 'temporalio/workflow'
require_relative 'coinbase_activity'
require_relative 'temporal_activity'

module CoinbaseRuby
class TemporalWorkflow < Temporalio::Workflow::Definition
def execute(name)
[
# Execute activity on Coinbase SDK worker
Temporalio::Workflow.execute_activity(CoinbaseActivity.name, name,
start_to_close_timeout: 10, task_queue: 'coinbase-ruby-sample-coinbase'),
# Execute activity on Temporal SDK worker
Temporalio::Workflow.execute_activity(TemporalActivity, name, start_to_close_timeout: 10)
]
end
end
end
47 changes: 47 additions & 0 deletions coinbase_ruby/worker.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# frozen_string_literal: true

# We must require Temporal SDK first and set the env var to prevent Coinbase SDK from trying to load its protos
require 'temporalio/client'
require 'temporalio/worker'
ENV['COINBASE_TEMPORAL_RUBY_DISABLE_PROTO_LOAD'] = '1'

require_relative 'coinbase_activity'
require_relative 'coinbase_workflow'
require_relative 'temporal_activity'
require_relative 'temporal_workflow'
require 'logger'
require 'temporal-ruby'
require 'temporal/worker'

# Create a Temporal client
client = Temporalio::Client.connect(
'localhost:7233',
'default',
logger: Logger.new($stdout, level: Logger::INFO)
)

# Create Temporal worker with the activity and workflow on the coinbase-ruby-sample-temporal task queue
worker = Temporalio::Worker.new(
client:,
task_queue: 'coinbase-ruby-sample-temporal',
activities: [CoinbaseRuby::TemporalActivity],
workflows: [CoinbaseRuby::TemporalWorkflow]
)

# Run the Temporal worker and inside it run the Coinbase worker
puts 'Starting worker on both Temporal Ruby SDK and Coinbase Ruby SDK'
worker.run do
# Configure Coinbase client/worker on the coinbase-ruby-sample-coinbase task queue
Temporal.configure do |config|
config.host = 'localhost'
config.port = 7233
config.namespace = 'default'
config.task_queue = 'coinbase-ruby-sample-coinbase'
end

# Run the Coinbase worker
worker = Temporal::Worker.new
worker.register_activity(CoinbaseRuby::CoinbaseActivity)
worker.register_workflow(CoinbaseRuby::CoinbaseWorkflow)
worker.start
end
75 changes: 75 additions & 0 deletions test/coinbase_ruby/workflow_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# frozen_string_literal: true

require 'securerandom'
require 'test'
require 'temporalio/testing'
require 'temporalio/worker'
ENV['COINBASE_TEMPORAL_RUBY_DISABLE_PROTO_LOAD'] = '1'
require 'temporal-ruby'
require 'temporal/worker'

require 'coinbase_ruby/coinbase_workflow'
require 'coinbase_ruby/temporal_workflow'

module CoinbaseRuby
class WorkflowTest < Test
def test_both_sdks
# Start a local env
Temporalio::Testing::WorkflowEnvironment.start_local do |env|
# Create Coinbase config, client, and worker
coinbase_config = Temporal::Configuration.new
host, port = env.client.connection.options.target_host.split(':')
coinbase_config.host = host
coinbase_config.port = port.to_i
coinbase_config.namespace = 'default'
coinbase_config.task_queue = 'coinbase-ruby-sample-coinbase'
coinbase_client = Temporal::Client.new(coinbase_config)
coinbase_worker = Temporal::Worker.new(coinbase_config)
coinbase_worker.register_activity(CoinbaseRuby::CoinbaseActivity)
coinbase_worker.register_workflow(CoinbaseRuby::CoinbaseWorkflow)

# Run all inside Temporal worker
worker = Temporalio::Worker.new(
client: env.client,
task_queue: 'coinbase-ruby-sample-temporal',
activities: [CoinbaseRuby::TemporalActivity],
workflows: [CoinbaseRuby::TemporalWorkflow]
)
worker.run do
# Run Coinbase worker in background, stop it when done
Thread.new { coinbase_worker.start }

# Run both workflows from Temporal client
assert_equal ['Hello from Coinbase Ruby SDK, user-a!', 'Hello from Temporal Ruby SDK, user-a!'],
env.client.execute_workflow(
CoinbaseRuby::CoinbaseWorkflow.name, 'user-a',
id: "wf-#{SecureRandom.uuid}", task_queue: 'coinbase-ruby-sample-coinbase'
)
assert_equal ['Hello from Coinbase Ruby SDK, user-b!', 'Hello from Temporal Ruby SDK, user-b!'],
env.client.execute_workflow(
CoinbaseRuby::TemporalWorkflow, 'user-b',
id: "wf-#{SecureRandom.uuid}", task_queue: 'coinbase-ruby-sample-temporal'
)

# Run both workflows from Coinbase client
workflow_id = "wf-#{SecureRandom.uuid}"
run_id = coinbase_client.start_workflow(
CoinbaseRuby::CoinbaseWorkflow, 'user-c',
options: { workflow_id:, task_queue: 'coinbase-ruby-sample-coinbase' }
)
assert_equal ['Hello from Coinbase Ruby SDK, user-c!', 'Hello from Temporal Ruby SDK, user-c!'],
coinbase_client.await_workflow_result(CoinbaseRuby::CoinbaseWorkflow, workflow_id:, run_id:)
workflow_id = "wf-#{SecureRandom.uuid}"
run_id = coinbase_client.start_workflow(
:TemporalWorkflow, 'user-d',
options: { workflow_id:, task_queue: 'coinbase-ruby-sample-temporal' }
)
assert_equal ['Hello from Coinbase Ruby SDK, user-d!', 'Hello from Temporal Ruby SDK, user-d!'],
coinbase_client.await_workflow_result(:TemporalWorkflow, workflow_id:, run_id:)
ensure
coinbase_worker.stop
end
end
end
end
end

0 comments on commit c440f5b

Please sign in to comment.