[DO NOT MERGE] Implement operator commands for Standalone Activities - #3013
Open
GregoryTravis wants to merge 58 commits into
Open
[DO NOT MERGE] Implement operator commands for Standalone Activities#3013GregoryTravis wants to merge 58 commits into
GregoryTravis wants to merge 58 commits into
Conversation
# Conflicts: # temporal-sdk/src/test/java/io/temporal/client/functional/StandaloneActivityTest.java
maciejdudko
requested changes
Aug 18, 2026
maciejdudko
left a comment
Contributor
There was a problem hiding this comment.
Looking good, although there are a few design choices that warrant more discussion.
Comment on lines
+423
to
+424
| private final @Nullable String reason; | ||
| private final @Nullable Duration jitter; |
Contributor
There was a problem hiding this comment.
Suggested change
| private final @Nullable String reason; | |
| private final @Nullable Duration jitter; | |
| private final UnpauseActivityOptions options; |
Contributor
Author
There was a problem hiding this comment.
@maciejdudko I also added one for Pause, even though there is just one field, for future proofing.
|
|
||
| UntypedActivityHandle handle = newHandle(); | ||
|
|
||
| handle.pause("because"); |
The review fix that added DescribeActivityOptions to DescribeActivityInput missed a third caller outside temporal-sdk, breaking CI: contrib/.../StandaloneActivityClientTracingTest.java:111: error: constructor DescribeActivityInput in class DescribeActivityInput cannot be applied to given types Local verification had only run :temporal-sdk:compileTestJava, which never touches contrib/. A bare `compileTestJava` covers all 16 modules.
The paused execution status was only asserted incidentally at the tail of updateOptionsOnPausedActivity. Cover the transition on its own: the same handle reports RUNNING before the pause and PAUSED after, on both the execution status and the run state. Matches the equivalent test in the Ruby, Python and Go suites.
An update naming nothing sent an empty field mask and silently changed nothing. Throw IllegalArgumentException before the round trip instead, pointing at restoreOriginalOptions for reverting. Matches Ruby, which raises ArgumentError, and Go and Python, which reject the same call.
unobservableRequestFields checked only reset_heartbeat. Set keep_paused and restore_original_options too and assert all three, since none of them is visible in any observable server state.
Ported from sdk-python#1782, written against our current API shape. Replaces describePayloadFieldsAreOptIn, describeReadsInputAndOutcome and describeReadsFailureOutcome 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 hasLastFailure true while getOutcomeFailure is null on a succeeded activity that failed once, the terminal-versus-attempt distinction that was untested. - asserts the accessors are absent, not merely that has* is false. The activity takes and returns Integer rather than int: MethodExtractor cannot probe a method reference with primitive types.
The four api#792 flags were covered only functionally, so nothing proved the SDK actually sets them on DescribeActivityExecutionRequest — a default-on bug would have looked identical from observable state. Three cases against a stubbed client: defaults ask for nothing, all four are forwarded, and asking for one does not set the others. Brings Java level with Python and Go.
The stripping in RootActivityClientInvoker 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.
It asserted that a single set option produces a mask naming exactly that option. The mask tests in every SDK already assert the mask names exactly what changed, and a one-option case catches nothing the multi-option case misses. Java was the only SDK with it, so removing it is also parity rather than porting three near-duplicates.
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.
Java clears the same way Go does, by passing a zero value rather than a dedicated sentinel: Duration.ZERO is non-null so the path reaches the mask, and the server normalizes a zero timeout back to unset. Null keeps the path out of the mask entirely. Neither behaviour was covered. Brings Java level with Go and Python.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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
DescribeActivityExecutionRequestgates four payload-bearing fields behindper-call flags (api#792). All four are now plumbed through
DescribeActivityOptionsand default to false.