-
Notifications
You must be signed in to change notification settings - Fork 5
Simple activity, context propagation, and message passing samples #20
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
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,46 @@ | ||
| AllCops: | ||
| NewCops: enable | ||
| TargetRubyVersion: 3.1 | ||
| SuggestExtensions: false | ||
| TargetRubyVersion: 3.2 | ||
| SuggestExtensions: false | ||
|
|
||
| # Don't need super for activities or workflows | ||
| Lint/MissingSuper: | ||
| AllowedParentClasses: | ||
| - Temporalio::Activity::Definition | ||
| - Temporalio::Workflow::Definition | ||
|
|
||
| # The default is too small and triggers simply setting lots of values on a proto | ||
| Metrics/AbcSize: | ||
| Max: 200 | ||
|
|
||
| # The default is too small | ||
| Metrics/BlockLength: | ||
| Max: 100 | ||
|
|
||
| # The default is too small | ||
| Metrics/ClassLength: | ||
| Max: 1000 | ||
|
|
||
| # The default is too small | ||
| Metrics/CyclomaticComplexity: | ||
| Max: 100 | ||
|
|
||
| # The default is too small | ||
| Metrics/MethodLength: | ||
| Max: 100 | ||
|
|
||
| # The default is too small | ||
| Metrics/ModuleLength: | ||
| Max: 1000 | ||
|
|
||
| # The default is too small | ||
| Metrics/PerceivedComplexity: | ||
| Max: 40 | ||
|
|
||
| # Don't need API docs for samples | ||
| Style/Documentation: | ||
| Enabled: false | ||
|
|
||
| # Don't need API docs for samples | ||
| Style/DocumentationMethod: | ||
| Enabled: false |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| # Activity Simple | ||
|
|
||
| This sample shows calling a couple of simple activities from a simple workflow. | ||
|
|
||
| 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 the workflow which will execute two activities and return. The output of the final command | ||
| should be: | ||
|
|
||
| ``` | ||
| Executing workflow | ||
| Workflow result: some-db-value from table some-db-table <appended-value> | ||
| ``` | ||
|
|
||
| There is also a [test](../test/activity_simple/my_workflow_test.rb) that demonstrates mocking an activity during the | ||
| test. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| # frozen_string_literal: true | ||
|
|
||
| require 'temporalio/activity' | ||
|
|
||
| module ActivitySimple | ||
| module MyActivities | ||
| # Fake database client | ||
| class MyDatabaseClient | ||
| def select_value(table) | ||
| "some-db-value from table #{table}" | ||
| end | ||
| end | ||
|
|
||
| # Stateful activity that is created only once by worker creation code | ||
| class SelectFromDatabase < Temporalio::Activity::Definition | ||
| def initialize(db_client) | ||
| @db_client = db_client | ||
| end | ||
|
|
||
| def execute(table) | ||
| @db_client.select_value(table) | ||
| end | ||
| end | ||
|
|
||
| # Stateless activity that is passed as class to worker creation code, | ||
| # thereby instantiating every attempt | ||
| class AppendSuffix < Temporalio::Activity::Definition | ||
| def execute(append_to) | ||
| "#{append_to} <appended-value>" | ||
| end | ||
| end | ||
| end | ||
| end | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| # frozen_string_literal: true | ||
|
|
||
| require 'temporalio/workflow' | ||
| require_relative 'my_activities' | ||
|
|
||
| module ActivitySimple | ||
| class MyWorkflow < Temporalio::Workflow::Definition | ||
| def execute | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please forgive reviewing API in the samples PR. I would have reached for
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
No prob, this is a good place. And I am happy to see others digging in to Ruby. Based on some ChatGPT ecosystem querying, it did seem |
||
| # Run an activity that needs some state like a database connection | ||
| result1 = Temporalio::Workflow.execute_activity( | ||
| MyActivities::SelectFromDatabase, | ||
| 'some-db-table', | ||
| start_to_close_timeout: 5 * 60 # 5 minutes | ||
| ) | ||
| Temporalio::Workflow.logger.info("Activity result 1: #{result1}") | ||
|
|
||
| # Run a stateless activity (note no difference on the caller side) | ||
| result2 = Temporalio::Workflow.execute_activity( | ||
| MyActivities::AppendSuffix, | ||
| result1, | ||
| start_to_close_timeout: 5 * 60 | ||
| ) | ||
| Temporalio::Workflow.logger.info("Activity result 2: #{result2}") | ||
|
|
||
| # We'll go ahead and return this result | ||
| result2 | ||
| end | ||
| end | ||
| end | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| # frozen_string_literal: true | ||
|
|
||
| require 'temporalio/client' | ||
| require_relative 'my_workflow' | ||
|
|
||
| # Create a client | ||
| client = Temporalio::Client.connect('localhost:7233', 'default') | ||
|
|
||
| # Run workflow | ||
| puts 'Executing workflow' | ||
| result = client.execute_workflow( | ||
| ActivitySimple::MyWorkflow, | ||
| id: 'activity-simple-sample-workflow-id', | ||
| task_queue: 'activity-simple-sample' | ||
| ) | ||
| puts "Workflow result: #{result}" |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| # frozen_string_literal: true | ||
|
|
||
| require_relative 'my_activities' | ||
| require_relative 'my_workflow' | ||
| require 'logger' | ||
| require 'temporalio/client' | ||
| require 'temporalio/worker' | ||
|
|
||
| # Create a Temporal client | ||
| client = Temporalio::Client.connect( | ||
| 'localhost:7233', | ||
| 'default', | ||
| logger: Logger.new($stdout, level: Logger::INFO) | ||
| ) | ||
|
|
||
| # Use an instance for the stateful DB activity, other activity we will pass | ||
| # in as class meaning it is instantiated each attempt | ||
| db_client = ActivitySimple::MyActivities::MyDatabaseClient.new | ||
| select_from_db_activity = ActivitySimple::MyActivities::SelectFromDatabase.new(db_client) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Isn't There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh ignore I see, only one of those is actually an activity. |
||
|
|
||
| # Create worker with the activities and workflow | ||
| worker = Temporalio::Worker.new( | ||
| client:, | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this syntax shorthand for
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes |
||
| task_queue: 'activity-simple-sample', | ||
| activities: [select_from_db_activity, ActivitySimple::MyActivities::AppendSuffix], | ||
| workflows: [ActivitySimple::MyWorkflow], | ||
| workflow_executor: Temporalio::Worker::WorkflowExecutor::ThreadPool.default | ||
cretz marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| ) | ||
|
|
||
| # Run the worker until SIGINT | ||
| puts 'Starting worker (ctrl+c to exit)' | ||
| worker.run(shutdown_signals: ['SIGINT']) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| # Context Propagation | ||
|
|
||
| This sample shows how a thread/fiber local can be propagated through workflows and activities using an interceptor. | ||
|
|
||
| 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 the workflow which will execute an activity and return. Note the log output from the worker | ||
| that contains logs on which user is calling the workflow/activity, information which we set as thread local on the | ||
| client and was automatically propagated through to the workflow and activity. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
probably worth adding a short sleep here to emphasize that we're faking I/O (as you do below in the message-passing sample)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Meh, not really needed that much (the async concepts of whether a sleep is present or not is different in Ruby and doesn't really mean anything) and wasn't done at https://github.com/temporalio/samples-dotnet/blob/main/src/ActivitySimple/MyActivities.cs either where it doesn't matter there either. But I may add this.