Implement operator commands for Standalone Activities - #3013
Implement operator commands for Standalone Activities#3013GregoryTravis wants to merge 65 commits into
Conversation
# Conflicts: # temporal-sdk/src/test/java/io/temporal/client/functional/StandaloneActivityTest.java
maciejdudko
left a comment
There was a problem hiding this comment.
Looking good, although there are a few design choices that warrant more discussion.
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.
|
|
||
| @Override | ||
| public String toString() { | ||
| return "PauseActivityOptions{" + "reason='" + reason + "'" + '}'; |
There was a problem hiding this comment.
Nit:
| return "PauseActivityOptions{" + "reason='" + reason + "'" + '}'; | |
| return "PauseActivityOptions{" + "reason='" + reason + "'}"; |
| /** | ||
| * Options for {@link UntypedActivityHandle#updateOptions(ActivityOptionsUpdate<?>...)}. | ||
| * | ||
| * <p>Only the fields that are explicitly set are sent to the server; a derived field mask ensures | ||
| * that unset fields are left unchanged (a partial update). | ||
| */ | ||
| @Experimental | ||
| public final class ActivityExecutionOptions { |
There was a problem hiding this comment.
Documentation is inaccurate with the new design.
| public static Builder newBuilder() { | ||
| return new Builder(); | ||
| } |
There was a problem hiding this comment.
With the new design, this class doesn't need a builder. Instead it should have a package-visibility constructor that takes proto ActivityOptions.
There was a problem hiding this comment.
I think it would be less confusing if ActivityOptionsKey was an inner class of ActivityOptionsUpdate, and the static constants in ActivityOptionsKeys were also moved into ActivityOptionsUpdate. I'd also remove the methods valueSet and valueUnset from ActivityOptionsUpdate and keep them only on ActivityOptionsKey. (and rename them to set and unset for brevity.)
| private final ActivityOptions activityOptions; | ||
| private final FieldMask updateMask; |
There was a problem hiding this comment.
UpdateActivityOptionsInput should receive List<ActivityOptionsUpdate> so that it can be intercepted, and the computation of activityOptions and updateMask should happen in RootActivityClientInvoker.
| switch (key.getName()) { | ||
| case "task_queue.name": | ||
| options.setTaskQueue(TaskQueue.newBuilder().setName((String) value).build()); | ||
| break; |
There was a problem hiding this comment.
The logic how to set the field in proto should be a method of ActivityOptionsKey itself, so that we don't have to match on the exact string value of the path. (Each key constant would have its own implementation.)
| @Experimental | ||
| public final class ActivityOptionsKey<T> { | ||
|
|
||
| private final String name; |
There was a problem hiding this comment.
Java SDK hasn't adopted the CHANGELOG.md file yet. Remove this.
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.