Skip to content

Demonstrate interoperability with Coinbase Ruby SDK #23

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Apr 29, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
6 changes: 6 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,14 @@

source 'https://rubygems.org'

# Primary Temporal dependency
gem 'temporalio'

# Some samples require certain dependencies, so they are in groups below alphabetically by group
# TODO(cretz): Move this to coinbase/temporal-ruby and off this fork/branch
# when https://github.com/coinbase/temporal-ruby/pull/335 merged, and then update the coinbase_ruby README
gem 'temporal-ruby', github: 'cretz/coinbase-temporal-ruby', branch: 'disable-proto-load-option', group: :coinbase_ruby

group :development do
gem 'minitest'
gem 'rake'
Expand Down
55 changes: 37 additions & 18 deletions Gemfile.lock
Original file line number Diff line number Diff line change
@@ -1,30 +1,48 @@
GIT
remote: https://github.com/cretz/coinbase-temporal-ruby.git
revision: debe21843b6214995fdcb1e4ea052f2b1075cc18
branch: disable-proto-load-option
specs:
temporal-ruby (0.1.1)
base64
grpc
oj

GEM
remote: https://rubygems.org/
specs:
ast (2.4.2)
base64 (0.2.0)
bigdecimal (3.1.9)
google-protobuf (4.30.2)
bigdecimal
rake (>= 13)
google-protobuf (4.30.2-aarch64-linux)
bigdecimal
rake (>= 13)
google-protobuf (4.30.2-arm64-darwin)
bigdecimal
rake (>= 13)
google-protobuf (4.30.2-x86-linux)
bigdecimal
rake (>= 13)
google-protobuf (4.30.2-x86_64-darwin)
bigdecimal
rake (>= 13)
google-protobuf (4.30.2-x86_64-linux)
bigdecimal
rake (>= 13)
google-protobuf (3.25.7)
googleapis-common-protos-types (1.19.0)
google-protobuf (>= 3.18, < 5.a)
grpc (1.71.0)
google-protobuf (>= 3.25, < 5.0)
googleapis-common-protos-types (~> 1.0)
grpc (1.71.0-aarch64-linux)
google-protobuf (>= 3.25, < 5.0)
googleapis-common-protos-types (~> 1.0)
grpc (1.71.0-arm64-darwin)
google-protobuf (>= 3.25, < 5.0)
googleapis-common-protos-types (~> 1.0)
grpc (1.71.0-x86-linux)
google-protobuf (>= 3.25, < 5.0)
googleapis-common-protos-types (~> 1.0)
grpc (1.71.0-x86_64-darwin)
google-protobuf (>= 3.25, < 5.0)
googleapis-common-protos-types (~> 1.0)
grpc (1.71.0-x86_64-linux)
google-protobuf (>= 3.25, < 5.0)
googleapis-common-protos-types (~> 1.0)
json (2.9.1)
language_server-protocol (3.17.0.3)
logger (1.7.0)
minitest (5.25.4)
oj (3.16.10)
bigdecimal (>= 3.0)
ostruct (>= 0.2)
ostruct (0.6.1)
parallel (1.26.3)
parser (3.3.6.0)
ast (~> 2.4.1)
Expand Down Expand Up @@ -77,6 +95,7 @@ DEPENDENCIES
minitest
rake
rubocop
temporal-ruby!
temporalio

BUNDLED WITH
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
28 changes: 28 additions & 0 deletions coinbase_ruby/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Coinbase Ruby

This sample shows a workflow, activity, and client from [Coinbase Ruby SDK](https://github.com/coinbase/temporal-ruby)
Copy link

@mjameswh mjameswh Feb 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This sample shows a workflow, activity, and client from Coinbase Ruby SDK able to interoperate with a workflow, activity, and client from Temporal Ruby SDK

Maybe that's just me, but the "… able to …" in the middle reads badly.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think "This sample shows [X] able to interoperate with [Y]" reads ok

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.

⚠️ NOTE - this requires disabling the loading of protos from the Coinbase Ruby SDK. As of this writing,
https://github.com/coinbase/temporal-ruby/pull/335 is not merged, so the Gemfile depends on the branch at
https://github.com/cretz/coinbase-temporal-ruby/tree/disable-proto-load-option for now.

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 run 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!"]
```
11 changes: 11 additions & 0 deletions coinbase_ruby/coinbase_activity.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# frozen_string_literal: true

require 'temporal-ruby'

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

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