Skip to content

💥 Standalone Activities for Ruby#443

Open
GregoryTravis wants to merge 38 commits into
mainfrom
gmt/ruby-standalone-activities
Open

💥 Standalone Activities for Ruby#443
GregoryTravis wants to merge 38 commits into
mainfrom
gmt/ruby-standalone-activities

Conversation

@GregoryTravis
Copy link
Copy Markdown
Contributor

Add standalone activity API (Client#start_activity + friends)

Introduces support for standalone activities — activities that execute independently of any workflow.

💥 Breaking Changes:

  • Activity::Info#workflow_id, #workflow_run_id, #workflow_type are now nullable (String?); they return nil when the activity is standalone.
  • Activity::Info#workflow_namespace is now marked @deprecated in favor of the new #namespace accessor. Both fields always carry the same value regardless of standalone-vs-workflow context; the rename matches the cross-SDK convention.

New public API surface:

  • Client#start_activity / Client#execute_activity — start a standalone activity execution by name, class, instance, or Activity::Definition::Info; execute_activity is start_activity + handle.result as a shortcut
  • Client#activity_handle(activity_id, activity_run_id:, result_hint:) — get a handle to an existing standalone activity (e.g. one started by a different process)
  • Client#list_activities(query) / Client#count_activities(query) — visibility queries over standalone activities; list_activities returns an Enumerator<ActivityExecution>
  • Client::ActivityHandle — handle returned by start_activity / activity_handle; provides #result(result_hint:, rpc_options:), #describe, #cancel(reason), #terminate(reason)
  • Client::ActivityExecution — lightweight metadata used in list_activities results
  • Client::ActivityExecution::Description — rich descriptor returned by ActivityHandle#describe; subclass of ActivityExecution. Exposes ~25 fields from the proto (status, attempt, retry_policy, last_failure, last_heartbeat_time, priority, canceled_reason, static_summary/static_details, etc.)
  • Client::ActivityExecutionCount + ::AggregationGroup — result of count_activities(), with group-by support
  • Client::ActivityExecutionStatus — enum module wrapping the proto's status values
  • ActivityIDReusePolicy + ActivityIDConflictPolicy — enum modules in lib/temporalio/common_enums.rb mirroring the workflow-side policies
  • Error::ActivityAlreadyStartedError (in error/failure.rb) — raised by start_activity when the server rejects a duplicate ID
  • Error::ActivityFailedError (in error.rb) — raised by handle.result when the activity terminates in failure; cause carries the underlying failure (ApplicationError, CanceledError, TimeoutError, TerminatedError)

New interceptor API:

  • Client::Interceptor::StartActivityInput, DescribeActivityInput, CancelActivityInput, TerminateActivityInput, ListActivitiesInput, CountActivitiesInput, FetchActivityOutcomeInput — seven new Data.define input types
  • Client::Interceptor::Outbound extended with seven matching pass-through methods (start_activity, describe_activity, cancel_activity, terminate_activity, list_activities, count_activities, fetch_activity_outcome)
  • Chain ordering convention is first-added-is-outermost.

Activity::Info additions:

  • #activity_run_id — run-scoped id assigned by the server to each standalone activity execution (nil for workflow-dispatched)
  • #namespace — canonical namespace accessor (preferred over the deprecated #workflow_namespace)
  • #in_workflow? — predicate distinguishing workflow-dispatched activities from standalone ones

Client#async_activity_handle extension (no new method):

  • Now accepts an ActivityIDReference constructed via ActivityIDReference.for_standalone(activity_id:, activity_run_id:).

ActivityIDReference additions:

  • ActivityIDReference.for_standalone(activity_id:, activity_run_id: nil) — class factory for the new standalone shape.
  • #standalone? — predicate for branching in async-completion routing

CI / dev server:

  • Enable standalone-activity server feature flags in the Temporal CLI dev server used by unit tests: frontend.activityAPIsEnabled, activity.enableStandalone, history.enableChasm, history.enableTransitionHistory (added to test/test.rb).
  • Bumped sdk-core submodule to a22517e4 (Rust crate 0.4.0) to pick up the worker-side coresdk.activity_task.Start.run_id proto field used to plumb activity_run_id into Activity::Info.

Tests:

  • test/client_activity_test.rb (28 tests) — integration tests covering the full lifecycle: start, execute, by-name, already-started, timeouts, failure-throws-ActivityFailedError, describe (running / terminated / canceled / retried / raw-info parity), state-transition-count, terminate-result-throws, polling-correctness (with timing assertions across one server long-poll deadline boundary), list, count, get-handle-with-nil-run-id, cancel-transitions-to-CANCELED, retry-policy / priority / id-reuse / id-conflict-policy round trips
  • test/client_activity_async_completion_test.rb (6 tests) — async completion via AsyncActivityHandle against a standalone ActivityIDReference: complete by activity_id, complete with run_id, heartbeat, fail, heartbeat+fail, report_cancellation
  • test/client_activity_hints_test.rb (6 tests) — definition hints used for client-side arg encode and worker-side decode, definition result_hint used for worker-side encode and client-side decode, call-site overrides on start_activity, by-name activities produce nil hints, handle.result(result_hint:) overrides, activity_handle(id, result_hint:) constructor-time hint, AsyncActivityHandle#complete(result, result_hint:) propagates the hint
  • test/client_activity_interceptor_chain_test.rb (5 tests) — multi-interceptor ordering for activity client calls; verifies first-added-is-outermost
  • test/client_workflow_interceptor_chain_test.rb (2 tests) — mirror of the above for the workflow client chain
  • test/activity_info_standalone_test.rb (2 tests) — Activity::Info standalone-vs-workflow fields asserted from inside the activity body
  • test/client/activity_id_reference_test.rb (5 tests) — factory shapes, for_standalone correctness, both forms coexist independently

Documentation:

  • README.md — added "Standalone Activities" subsection under "Activities" with five runnable code examples (start, execute, get-handle + describe/result/cancel/terminate, list/count, in-activity-body context introspection)

…ds, and new nullability for old fields, and a factory for creating the standalone version.

Enums for activity id reuse and conflict policies.
SAA-specific errors.
…e polling.

Add test_async_completion_heartbeat_and_fail_standalone in addition to previous heartbeat test.
Don’t use queue mechanism for gathering id info when it can be gotten directly.
Consistency of parameter names and ordering.
Add static_details.
Use constant for “activity:” prefix.
@GregoryTravis GregoryTravis requested a review from a team as a code owner May 19, 2026 21:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant