Skip to content

[DO NOT MERGE] Implement operator commands for Standalone Activities - #543

Open
GregoryTravis wants to merge 65 commits into
mainfrom
gmt/operator-commands
Open

[DO NOT MERGE] Implement operator commands for Standalone Activities#543
GregoryTravis wants to merge 65 commits into
mainfrom
gmt/operator-commands

Conversation

@GregoryTravis

@GregoryTravis GregoryTravis commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

Implement operator commands for standalone activities

Adds pause, unpause, reset, and update-options to standalone activities, plus
the describe surface needed to observe their effects.

Standalone activities already supported start, result, describe, cancel, and
terminate. This adds the four operator commands the server exposes for them, so
an operator can hold, resume, restart, and retune a running activity without
going through a workflow.

Describe: payload fields are opt-in

DescribeActivityExecutionRequest gates four payload-bearing fields behind
per-call flags (api#792). All four are now plumbed through describe and
default to false.

GregoryTravis and others added 30 commits June 18, 2026 15:50
…e + bridge updates)

# Conflicts:
#	temporalio/ext/sdk-core
#	temporalio/lib/temporalio/api/enums/v1/failed_cause.rb
#	temporalio/lib/temporalio/api/namespace/v1/message.rb
#	temporalio/lib/temporalio/api/workflowservice/v1/request_response.rb
#	temporalio/sig/temporalio/api/enums/v1/failed_cause.rbs
…in + api overlay + api-adapter fixups), Cargo.lock regenerated, pin Ruby 3.3.11
update_options(heartbeat_timeout: nil) raised rather than clearing the
option: seconds_to_duration returns nil for a nil value, and assigning
nil through the proto bracket accessor throws

  Google::Protobuf::TypeError: nil message not allowed here

Skip the assignment when the value is nil, leaving the field unset while
the mask still names the path — the same shape Python uses. The
neighbouring task_queue, retry_policy and priority fields were already
nil-safe; only the duration loop was affected.

Adds the test that found it.
test_unobservable_request_fields asserted the reset jitter and request id
but none of the three boolean flags. Set keep_paused,
restore_original_options and reset_heartbeat and assert each reaches the
wire.

Brings Ruby level with Python and Go.
Description#input(hints:) and #result(result_hint:) existed with zero
coverage of the hint argument — the describe payloads come back
undecoded, so the hints are supplied at read time and nothing verified
they were forwarded.

Added to client_activity_hints_test.rb, which already has the tracking
payload converter this needs. Go and Java already cover their equivalents
(typed pointers and EncodedValues.get(i, Class)); Python has no hint
parameter until sdk-python#1782 lands.
Ported from sdk-python#1782, written against our current API shape.

Replaces test_describe_payload_fields_are_opt_in,
test_describe_input_and_result_are_opt_in and test_describe_outcome_failure
with one test covering all three, and more:

- a new HeartbeatFailIncrementActivity heartbeats, fails once, then
  succeeds, so a single describe carries input, result, heartbeat details
  and a last failure at the same time. The three tests it replaces each
  used a different activity, so no describe ever held them together.
- pins has_last_failure? true while failure (the terminal outcome) is nil
  on a succeeded activity that failed once, the distinction that was
  untested.
- asserts the accessors are empty or nil, not merely that has_* is false.
The nilable Error::Failure could not be narrowed inline.
The four api#792 flags were covered only functionally, so nothing proved
the SDK actually sets them on the describe request — a default-on bug
would have looked identical from observable state.

Three cases against a stubbed service: defaults ask for nothing, all four
are forwarded, and asking for one does not set the others.

Brings Ruby level with Python and Go.
The stripping in the client implementation existed with no coverage. It
only matters against a server that ignores the opt-ins, which no
functional test can produce, so it needs a stub that returns every
payload field regardless of what was asked for.

Three cases: nothing requested strips all four, everything requested
keeps all four, and stripping is per field.
RestoreOriginalOptions reuses the update-options interceptor rather than
having one of its own, distinguished purely by the restore flag with an
empty mask. An interceptor watching option updates would otherwise
silently miss restores, and nothing pinned that.

Ported from the Python interceptor suite, which was the only one
asserting it.
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.

3 participants