diff --git a/temporal-sdk/src/main/java/io/temporal/internal/common/SdkFlag.java b/temporal-sdk/src/main/java/io/temporal/internal/common/SdkFlag.java new file mode 100644 index 000000000..658b44e0d --- /dev/null +++ b/temporal-sdk/src/main/java/io/temporal/internal/common/SdkFlag.java @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2022 Temporal Technologies, Inc. All Rights Reserved. + * + * Copyright (C) 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this material except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.temporal.internal.common; + +/** + * SdkFlag represents a flag used to help version the sdk internally to make breaking changes in + * workflow logic. + */ +public enum SdkFlag { + UNSET(0), + /* + * Changes behavior of GetVersion to not yield if no previous call existed in history. + */ + SKIP_YIELD_ON_DEFAULT_VERSION(1), + UNKNOWN(Integer.MAX_VALUE); + + private final int value; + + SdkFlag(int value) { + this.value = value; + } + + public boolean compare(int i) { + return value == i; + } + + public static SdkFlag getValue(int id) { + SdkFlag[] as = SdkFlag.values(); + for (int i = 0; i < as.length; i++) { + if (as[i].compare(id)) return as[i]; + } + return SdkFlag.UNKNOWN; + } + + public int getValue() { + return value; + } +} diff --git a/temporal-sdk/src/main/java/io/temporal/internal/common/SdkFlags.java b/temporal-sdk/src/main/java/io/temporal/internal/common/SdkFlags.java new file mode 100644 index 000000000..c61d5a748 --- /dev/null +++ b/temporal-sdk/src/main/java/io/temporal/internal/common/SdkFlags.java @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2022 Temporal Technologies, Inc. All Rights Reserved. + * + * Copyright (C) 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this material except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.temporal.internal.common; + +import io.temporal.workflow.Functions; +import java.util.EnumSet; + +/** Represents all the flags that are currently set in a workflow execution. */ +public final class SdkFlags { + private final boolean supportSdkMetadata; + private final Functions.Func replaying; + // Flags that have been received from the server or have not been sent yet. + private final EnumSet sdkFlags = EnumSet.noneOf(SdkFlag.class); + // Flags that have been set this WFT that have not been sent to the server. + // Keep track of them separately, so we know what to send to the server. + private final EnumSet unsentSdkFlags = EnumSet.noneOf(SdkFlag.class); + + public SdkFlags(boolean supportSdkMetadata, Functions.Func replaying) { + this.supportSdkMetadata = supportSdkMetadata; + this.replaying = replaying; + } + + /** + * Marks a flag as usable regardless of replay status. + * + * @return True, as long as the server supports SDK flags + */ + public boolean setSdkFlag(SdkFlag flag) { + if (!supportSdkMetadata) { + return false; + } + sdkFlags.add(flag); + return true; + } + + /** + * @return True if this flag may currently be used. + */ + public boolean tryUseSdkFlag(SdkFlag flag) { + if (!supportSdkMetadata) { + return false; + } + + if (!replaying.apply()) { + sdkFlags.add(flag); + unsentSdkFlags.add(flag); + return true; + } else { + return sdkFlags.contains(flag); + } + } + + /** + * @return All flags set since the last call to takeNewSdkFlags. + */ + public EnumSet takeNewSdkFlags() { + EnumSet result = unsentSdkFlags.clone(); + unsentSdkFlags.clear(); + return result; + } +} diff --git a/temporal-sdk/src/main/java/io/temporal/internal/replay/ReplayWorkflowContext.java b/temporal-sdk/src/main/java/io/temporal/internal/replay/ReplayWorkflowContext.java index 18d2515d9..7de95e848 100644 --- a/temporal-sdk/src/main/java/io/temporal/internal/replay/ReplayWorkflowContext.java +++ b/temporal-sdk/src/main/java/io/temporal/internal/replay/ReplayWorkflowContext.java @@ -26,6 +26,7 @@ import io.temporal.api.common.v1.*; import io.temporal.api.failure.v1.Failure; import io.temporal.api.workflowservice.v1.PollWorkflowTaskQueueResponse; +import io.temporal.internal.common.SdkFlag; import io.temporal.internal.statemachines.ExecuteActivityParameters; import io.temporal.internal.statemachines.ExecuteLocalActivityParameters; import io.temporal.internal.statemachines.LocalActivityCallback; @@ -269,8 +270,9 @@ void mutableSideEffect( * @param minSupported min version supported for the change * @param maxSupported max version supported for the change * @param callback used to return version + * @return True if the identifier is not present in history */ - void getVersion( + boolean getVersion( String changeId, int minSupported, int maxSupported, @@ -382,4 +384,9 @@ void getVersion( /** Updates or inserts search attributes used to index workflows. */ void upsertSearchAttributes(@Nonnull SearchAttributes searchAttributes); + + /** + * @return true if this flag may currently be used. + */ + boolean tryUseSdkFlag(SdkFlag flag); } diff --git a/temporal-sdk/src/main/java/io/temporal/internal/replay/ReplayWorkflowContextImpl.java b/temporal-sdk/src/main/java/io/temporal/internal/replay/ReplayWorkflowContextImpl.java index 0e7cd8c92..45277f252 100644 --- a/temporal-sdk/src/main/java/io/temporal/internal/replay/ReplayWorkflowContextImpl.java +++ b/temporal-sdk/src/main/java/io/temporal/internal/replay/ReplayWorkflowContextImpl.java @@ -32,6 +32,7 @@ import io.temporal.api.history.v1.WorkflowExecutionStartedEventAttributes; import io.temporal.failure.CanceledFailure; import io.temporal.internal.common.ProtobufTimeUtils; +import io.temporal.internal.common.SdkFlag; import io.temporal.internal.statemachines.*; import io.temporal.internal.worker.SingleWorkerOptions; import io.temporal.workflow.Functions; @@ -240,6 +241,11 @@ public boolean isReplaying() { return workflowStateMachines.isReplaying(); } + @Override + public boolean tryUseSdkFlag(SdkFlag flag) { + return workflowStateMachines.tryUseSdkFlag(flag); + } + @Override public Functions.Proc1 newTimer( Duration delay, Functions.Proc1 callback) { @@ -290,12 +296,12 @@ public void mutableSideEffect( } @Override - public void getVersion( + public boolean getVersion( String changeId, int minSupported, int maxSupported, Functions.Proc2 callback) { - workflowStateMachines.getVersion(changeId, minSupported, maxSupported, callback); + return workflowStateMachines.getVersion(changeId, minSupported, maxSupported, callback); } @Override diff --git a/temporal-sdk/src/main/java/io/temporal/internal/replay/ReplayWorkflowRunTaskHandler.java b/temporal-sdk/src/main/java/io/temporal/internal/replay/ReplayWorkflowRunTaskHandler.java index 29538ec65..1f6571dbf 100644 --- a/temporal-sdk/src/main/java/io/temporal/internal/replay/ReplayWorkflowRunTaskHandler.java +++ b/temporal-sdk/src/main/java/io/temporal/internal/replay/ReplayWorkflowRunTaskHandler.java @@ -39,8 +39,10 @@ import io.temporal.api.protocol.v1.Message; import io.temporal.api.query.v1.WorkflowQuery; import io.temporal.api.query.v1.WorkflowQueryResult; +import io.temporal.api.workflowservice.v1.GetSystemInfoResponse; import io.temporal.api.workflowservice.v1.PollWorkflowTaskQueueResponseOrBuilder; import io.temporal.internal.Config; +import io.temporal.internal.common.SdkFlag; import io.temporal.internal.common.UpdateMessage; import io.temporal.internal.statemachines.ExecuteLocalActivityParameters; import io.temporal.internal.statemachines.StatesMachinesCallback; @@ -90,13 +92,16 @@ class ReplayWorkflowRunTaskHandler implements WorkflowRunTaskHandler { private final ReplayWorkflowExecutor replayWorkflowExecutor; + private final GetSystemInfoResponse.Capabilities capabilities; + ReplayWorkflowRunTaskHandler( String namespace, ReplayWorkflow workflow, PollWorkflowTaskQueueResponseOrBuilder workflowTask, SingleWorkerOptions workerOptions, Scope metricsScope, - LocalActivityDispatcher localActivityDispatcher) { + LocalActivityDispatcher localActivityDispatcher, + GetSystemInfoResponse.Capabilities capabilities) { HistoryEvent startedEvent = workflowTask.getHistory().getEvents(0); if (!startedEvent.hasWorkflowExecutionStartedEventAttributes()) { throw new IllegalArgumentException( @@ -107,7 +112,8 @@ class ReplayWorkflowRunTaskHandler implements WorkflowRunTaskHandler { this.localActivityDispatcher = localActivityDispatcher; this.workflow = workflow; - this.workflowStateMachines = new WorkflowStateMachines(new StatesMachinesCallbackImpl()); + this.workflowStateMachines = + new WorkflowStateMachines(new StatesMachinesCallbackImpl(), capabilities); String fullReplayDirectQueryType = workflowTask.hasQuery() ? workflowTask.getQuery().getQueryType() : null; this.context = @@ -125,6 +131,7 @@ class ReplayWorkflowRunTaskHandler implements WorkflowRunTaskHandler { new ReplayWorkflowExecutor(workflow, workflowStateMachines, context); this.localActivityCompletionSink = localActivityCompletionQueue::add; this.localActivityMeteringHelper = new LocalActivityMeteringHelper(); + this.capabilities = capabilities; } @Override @@ -159,6 +166,11 @@ public WorkflowTaskResult handleWorkflowTask( processLocalActivityRequests(wftHearbeatDeadline); List commands = workflowStateMachines.takeCommands(); List messages = workflowStateMachines.takeMessages(); + EnumSet newFlags = workflowStateMachines.takeNewSdkFlags(); + List newSdkFlags = new ArrayList<>(newFlags.size()); + for (SdkFlag flag : newFlags) { + newSdkFlags.add(flag.getValue()); + } if (context.isWorkflowMethodCompleted()) { // it's important for query, otherwise the WorkflowTaskHandler is responsible for closing // and invalidation @@ -175,6 +187,7 @@ public WorkflowTaskResult handleWorkflowTask( .setFinalCommand(context.isWorkflowMethodCompleted()) .setForceWorkflowTask(localActivityTaskCount > 0 && !context.isWorkflowMethodCompleted()) .setNonfirstLocalActivityAttempts(localActivityMeteringHelper.getNonfirstAttempts()) + .setSdkFlags(newSdkFlags) .build(); } finally { lock.unlock(); diff --git a/temporal-sdk/src/main/java/io/temporal/internal/replay/ReplayWorkflowTaskHandler.java b/temporal-sdk/src/main/java/io/temporal/internal/replay/ReplayWorkflowTaskHandler.java index 07f1573d2..42dbcb5e3 100644 --- a/temporal-sdk/src/main/java/io/temporal/internal/replay/ReplayWorkflowTaskHandler.java +++ b/temporal-sdk/src/main/java/io/temporal/internal/replay/ReplayWorkflowTaskHandler.java @@ -36,6 +36,7 @@ import io.temporal.api.failure.v1.Failure; import io.temporal.api.history.v1.HistoryEvent; import io.temporal.api.query.v1.WorkflowQuery; +import io.temporal.api.sdk.v1.WorkflowTaskCompletedMetadata; import io.temporal.api.taskqueue.v1.StickyExecutionAttributes; import io.temporal.api.taskqueue.v1.TaskQueue; import io.temporal.api.workflowservice.v1.*; @@ -235,6 +236,13 @@ private Result createCompletedWFTRequest( } completedRequest.setStickyAttributes(attributes); } + if (!result.getSdkFlags().isEmpty()) { + completedRequest = + completedRequest.setSdkMetadata( + WorkflowTaskCompletedMetadata.newBuilder() + .addAllLangUsedFlags(result.getSdkFlags()) + .build()); + } return new Result( workflowType, completedRequest.build(), @@ -383,7 +391,13 @@ private WorkflowRunTaskHandler createStatefulHandler( } ReplayWorkflow workflow = workflowFactory.getWorkflow(workflowType, workflowExecution); return new ReplayWorkflowRunTaskHandler( - namespace, workflow, workflowTask, options, metricsScope, localActivityDispatcher); + namespace, + workflow, + workflowTask, + options, + metricsScope, + localActivityDispatcher, + service.getServerCapabilities().get()); } private void resetStickyTaskQueue(WorkflowExecution execution) { diff --git a/temporal-sdk/src/main/java/io/temporal/internal/replay/WorkflowTaskResult.java b/temporal-sdk/src/main/java/io/temporal/internal/replay/WorkflowTaskResult.java index a2a3f827c..bb07ee3fe 100644 --- a/temporal-sdk/src/main/java/io/temporal/internal/replay/WorkflowTaskResult.java +++ b/temporal-sdk/src/main/java/io/temporal/internal/replay/WorkflowTaskResult.java @@ -40,6 +40,7 @@ public static final class Builder { private Map queryResults; private boolean forceWorkflowTask; private int nonfirstLocalActivityAttempts; + private List sdkFlags; public Builder setCommands(List commands) { this.commands = commands; @@ -71,6 +72,11 @@ public Builder setNonfirstLocalActivityAttempts(int nonfirstLocalActivityAttempt return this; } + public Builder setSdkFlags(List sdkFlags) { + this.sdkFlags = sdkFlags; + return this; + } + public WorkflowTaskResult build() { return new WorkflowTaskResult( commands == null ? Collections.emptyList() : commands, @@ -78,7 +84,8 @@ public WorkflowTaskResult build() { queryResults == null ? Collections.emptyMap() : queryResults, finalCommand, forceWorkflowTask, - nonfirstLocalActivityAttempts); + nonfirstLocalActivityAttempts, + sdkFlags == null ? Collections.emptyList() : sdkFlags); } } @@ -88,6 +95,7 @@ public WorkflowTaskResult build() { private final Map queryResults; private final boolean forceWorkflowTask; private final int nonfirstLocalActivityAttempts; + private final List sdkFlags; private WorkflowTaskResult( List commands, @@ -95,7 +103,8 @@ private WorkflowTaskResult( Map queryResults, boolean finalCommand, boolean forceWorkflowTask, - int nonfirstLocalActivityAttempts) { + int nonfirstLocalActivityAttempts, + List sdkFlags) { this.commands = commands; this.messages = messages; this.nonfirstLocalActivityAttempts = nonfirstLocalActivityAttempts; @@ -105,6 +114,7 @@ private WorkflowTaskResult( this.queryResults = queryResults; this.finalCommand = finalCommand; this.forceWorkflowTask = forceWorkflowTask; + this.sdkFlags = sdkFlags; } public List getCommands() { @@ -131,4 +141,8 @@ public boolean isForceWorkflowTask() { public int getNonfirstLocalActivityAttempts() { return nonfirstLocalActivityAttempts; } + + public List getSdkFlags() { + return sdkFlags; + } } diff --git a/temporal-sdk/src/main/java/io/temporal/internal/statemachines/VersionStateMachine.java b/temporal-sdk/src/main/java/io/temporal/internal/statemachines/VersionStateMachine.java index 27705ead1..7577408cd 100644 --- a/temporal-sdk/src/main/java/io/temporal/internal/statemachines/VersionStateMachine.java +++ b/temporal-sdk/src/main/java/io/temporal/internal/statemachines/VersionStateMachine.java @@ -369,11 +369,12 @@ private VersionStateMachine( this.stateMachineSink = stateMachineSink; } - public void getVersion( + public State getVersion( int minSupported, int maxSupported, Functions.Proc2 callback) { InvocationStateMachine ism = new InvocationStateMachine(minSupported, maxSupported, callback); ism.explicitEvent(ExplicitEvent.CHECK_EXECUTION_STATE); ism.explicitEvent(ExplicitEvent.SCHEDULE); + return ism.getState(); } public void handleNonMatchingEvent(HistoryEvent event) { diff --git a/temporal-sdk/src/main/java/io/temporal/internal/statemachines/WorkflowStateMachines.java b/temporal-sdk/src/main/java/io/temporal/internal/statemachines/WorkflowStateMachines.java index be82caea4..d5dbc6257 100644 --- a/temporal-sdk/src/main/java/io/temporal/internal/statemachines/WorkflowStateMachines.java +++ b/temporal-sdk/src/main/java/io/temporal/internal/statemachines/WorkflowStateMachines.java @@ -37,10 +37,9 @@ import io.temporal.api.failure.v1.Failure; import io.temporal.api.history.v1.*; import io.temporal.api.protocol.v1.Message; +import io.temporal.api.workflowservice.v1.GetSystemInfoResponse; import io.temporal.failure.CanceledFailure; -import io.temporal.internal.common.ProtocolType; -import io.temporal.internal.common.ProtocolUtils; -import io.temporal.internal.common.WorkflowExecutionUtils; +import io.temporal.internal.common.*; import io.temporal.internal.history.LocalActivityMarkerUtils; import io.temporal.internal.history.VersionMarkerUtils; import io.temporal.internal.sync.WorkflowThread; @@ -58,6 +57,10 @@ enum HandleEventStatus { NON_MATCHING_EVENT } + /** Initial set of SDK flags that will be set on all new workflow executions. */ + private static final List initialFlags = + Collections.unmodifiableList(Arrays.asList(SdkFlag.SKIP_YIELD_ON_DEFAULT_VERSION)); + /** * EventId of the WorkflowTaskStarted event of the Workflow Task that was picked up by a worker * and triggered a current replay or execution. It's expected to be the last event in the history @@ -148,11 +151,25 @@ enum HandleEventStatus { private final WFTBuffer wftBuffer = new WFTBuffer(); - /** */ private List messages = new ArrayList(); - public WorkflowStateMachines(StatesMachinesCallback callbacks) { - this(callbacks, (stateMachine) -> {}); + private final SdkFlags flags; + + public WorkflowStateMachines( + StatesMachinesCallback callbacks, GetSystemInfoResponse.Capabilities capabilities) { + this(callbacks, (stateMachine) -> {}, capabilities); + } + + @VisibleForTesting + public WorkflowStateMachines( + StatesMachinesCallback callbacks, + Functions.Proc1 stateMachineSink, + GetSystemInfoResponse.Capabilities capabilities) { + this.callbacks = Objects.requireNonNull(callbacks); + this.commandSink = cancellableCommands::add; + this.stateMachineSink = stateMachineSink; + this.localActivityRequestSink = (request) -> localActivityRequests.add(request); + this.flags = new SdkFlags(capabilities.getSdkMetadata(), this::isReplaying); } @VisibleForTesting @@ -162,6 +179,7 @@ public WorkflowStateMachines( this.commandSink = cancellableCommands::add; this.stateMachineSink = stateMachineSink; this.localActivityRequestSink = (request) -> localActivityRequests.add(request); + this.flags = new SdkFlags(false, this::isReplaying); } // TODO revisit and potentially remove workflowTaskStartedEventId at all from the state machines. @@ -231,32 +249,15 @@ public void handleEvent(HistoryEvent event, boolean hasNextEvent) { * this batch contains the last events of the history */ private void handleEventsBatch(List events, boolean hasNextEvent) { - if (EventType.EVENT_TYPE_WORKFLOW_TASK_STARTED.equals(events.get(0).getEventType())) { - for (HistoryEvent event : events) { - try { - preloadVersionMarker(event); - } catch (RuntimeException e) { - throw createEventProcessingException(e, event); - } + if (EventType.EVENT_TYPE_WORKFLOW_EXECUTION_STARTED.equals(events.get(0).getEventType())) { + for (SdkFlag flag : initialFlags) { + flags.tryUseSdkFlag(flag); } } - // Look ahead to infer protocol messages if (EventType.EVENT_TYPE_WORKFLOW_TASK_STARTED.equals(events.get(0).getEventType())) { - if (this.isReplaying()) { - for (HistoryEvent event : events) { - if (event.hasWorkflowExecutionUpdateAcceptedEventAttributes()) { - WorkflowExecutionUpdateAcceptedEventAttributes updateEvent = - event.getWorkflowExecutionUpdateAcceptedEventAttributes(); - this.messages.add( - Message.newBuilder() - .setId(updateEvent.getAcceptedRequestMessageId()) - .setProtocolInstanceId(updateEvent.getProtocolInstanceId()) - .setEventId(updateEvent.getAcceptedRequestSequencingEventId()) - .setBody(Any.pack(updateEvent.getAcceptedRequest())) - .build()); - } - } + for (HistoryEvent event : events) { + handleSingleEventLookahead(event); } } @@ -281,6 +282,43 @@ private void handleEventsBatch(List events, boolean hasNextEvent) } } + /** Handle an event when looking ahead at history during replay */ + private void handleSingleEventLookahead(HistoryEvent event) { + EventType eventType = event.getEventType(); + switch (eventType) { + case EVENT_TYPE_MARKER_RECORDED: + try { + preloadVersionMarker(event); + } catch (RuntimeException e) { + throw createEventProcessingException(e, event); + } + break; + case EVENT_TYPE_WORKFLOW_EXECUTION_UPDATE_ACCEPTED: + // Look ahead to infer protocol messages + WorkflowExecutionUpdateAcceptedEventAttributes updateEvent = + event.getWorkflowExecutionUpdateAcceptedEventAttributes(); + this.messages.add( + Message.newBuilder() + .setId(updateEvent.getAcceptedRequestMessageId()) + .setProtocolInstanceId(updateEvent.getProtocolInstanceId()) + .setEventId(updateEvent.getAcceptedRequestSequencingEventId()) + .setBody(Any.pack(updateEvent.getAcceptedRequest())) + .build()); + break; + case EVENT_TYPE_WORKFLOW_TASK_COMPLETED: + WorkflowTaskCompletedEventAttributes completedEvent = + event.getWorkflowTaskCompletedEventAttributes(); + for (Integer flag : completedEvent.getSdkMetadata().getLangUsedFlagsList()) { + SdkFlag sdkFlag = SdkFlag.getValue(flag); + if (sdkFlag.equals(SdkFlag.UNKNOWN)) { + throw new IllegalArgumentException("Unknown SDK flag:" + flag); + } + flags.setSdkFlag(sdkFlag); + } + break; + } + } + private List takeLTE(long eventId) { List m = new ArrayList(); List remainingMessages = new ArrayList(); @@ -516,6 +554,20 @@ public List takeMessages() { return result; } + /** + * @return True if the SDK flag is supported in this workflow execution + */ + public boolean tryUseSdkFlag(SdkFlag flag) { + return flags.tryUseSdkFlag(flag); + } + + /** + * @return Set of all new flags set since the last call + */ + public EnumSet takeNewSdkFlags() { + return flags.takeNewSdkFlags(); + } + private void prepareCommands() { if (preparing) { return; @@ -862,7 +914,7 @@ public void mutableSideEffect( stateMachineSink); } - public void getVersion( + public boolean getVersion( String changeId, int minSupported, int maxSupported, @@ -870,19 +922,22 @@ public void getVersion( VersionStateMachine stateMachine = versions.computeIfAbsent( changeId, - (idKey) -> - VersionStateMachine.newInstance( - changeId, this::isReplaying, commandSink, stateMachineSink)); - stateMachine.getVersion( - minSupported, - maxSupported, - (v, e) -> { - callback.apply(v, e); - // without this getVersion call will trigger the end of WFT, - // instead we want to prepare subsequent commands and unblock the execution one more - // time. - eventLoop(); - }); + (idKey) -> { + return VersionStateMachine.newInstance( + changeId, this::isReplaying, commandSink, stateMachineSink); + }); + VersionStateMachine.State state = + stateMachine.getVersion( + minSupported, + maxSupported, + (v, e) -> { + callback.apply(v, e); + // without this getVersion call will trigger the end of WFT, + // instead we want to prepare subsequent commands and unblock the execution one more + // time. + eventLoop(); + }); + return state != VersionStateMachine.State.SKIPPED_REPLAYING; } public List takeLocalActivityRequests() { diff --git a/temporal-sdk/src/main/java/io/temporal/internal/sync/SyncWorkflowContext.java b/temporal-sdk/src/main/java/io/temporal/internal/sync/SyncWorkflowContext.java index 2d16b0442..8c92cb519 100644 --- a/temporal-sdk/src/main/java/io/temporal/internal/sync/SyncWorkflowContext.java +++ b/temporal-sdk/src/main/java/io/temporal/internal/sync/SyncWorkflowContext.java @@ -23,6 +23,7 @@ import static io.temporal.internal.common.HeaderUtils.intoPayloadMap; import static io.temporal.internal.common.HeaderUtils.toHeaderGrpc; import static io.temporal.internal.common.SerializerUtils.toRetryPolicy; +import static io.temporal.internal.sync.WorkflowInternal.DEFAULT_VERSION; import com.google.common.base.MoreObjects; import com.google.common.base.Preconditions; @@ -57,6 +58,7 @@ import io.temporal.internal.common.ActivityOptionUtils; import io.temporal.internal.common.OptionsUtils; import io.temporal.internal.common.ProtobufTimeUtils; +import io.temporal.internal.common.SdkFlag; import io.temporal.internal.common.SearchAttributesUtil; import io.temporal.internal.replay.ChildWorkflowTaskFailedException; import io.temporal.internal.replay.ReplayWorkflowContext; @@ -913,20 +915,33 @@ private R mutableSideEffectImpl( @Override public int getVersion(String changeId, int minSupported, int maxSupported) { CompletablePromise result = Workflow.newPromise(); - replayContext.getVersion( - changeId, - minSupported, - maxSupported, - (v, e) -> - runner.executeInWorkflowThread( - "version-callback", - () -> { - if (v != null) { - result.complete(v); - } else { - result.completeExceptionally(e); - } - })); + boolean markerExists = + replayContext.getVersion( + changeId, + minSupported, + maxSupported, + (v, e) -> + runner.executeInWorkflowThread( + "version-callback", + () -> { + if (v != null) { + result.complete(v); + } else { + result.completeExceptionally(e); + } + })); + /* + * If we are replaying a workflow and encounter a getVersion call it is possible that this call did not exist + * on the original execution. If the call did not exist on the original execution then we cannot block on results + * because it can lead to non-deterministic scheduling. + * */ + if (replayContext.isReplaying() + && !markerExists + && replayContext.tryUseSdkFlag(SdkFlag.SKIP_YIELD_ON_DEFAULT_VERSION) + && minSupported == DEFAULT_VERSION) { + return DEFAULT_VERSION; + } + try { return result.get(); } catch (UnsupportedVersion.UnsupportedVersionException ex) { diff --git a/temporal-sdk/src/test/java/io/temporal/internal/replay/OutdatedDirectQueryReplayWorkflowRunTaskHandlerTest.java b/temporal-sdk/src/test/java/io/temporal/internal/replay/OutdatedDirectQueryReplayWorkflowRunTaskHandlerTest.java index d8ffb28f9..d8e6faa8d 100644 --- a/temporal-sdk/src/test/java/io/temporal/internal/replay/OutdatedDirectQueryReplayWorkflowRunTaskHandlerTest.java +++ b/temporal-sdk/src/test/java/io/temporal/internal/replay/OutdatedDirectQueryReplayWorkflowRunTaskHandlerTest.java @@ -33,6 +33,7 @@ import io.temporal.api.enums.v1.EventType; import io.temporal.api.history.v1.History; import io.temporal.api.query.v1.WorkflowQuery; +import io.temporal.api.workflowservice.v1.GetSystemInfoResponse; import io.temporal.api.workflowservice.v1.PollActivityTaskQueueResponse; import io.temporal.api.workflowservice.v1.PollWorkflowTaskQueueResponse; import io.temporal.api.workflowservice.v1.PollWorkflowTaskQueueResponseOrBuilder; @@ -102,7 +103,8 @@ public void queryIsOutdated() throws Throwable { wft, SingleWorkerOptions.newBuilder().build(), new NoopScope(), - mock(LocalActivityDispatcher.class)); + mock(LocalActivityDispatcher.class), + GetSystemInfoResponse.Capabilities.newBuilder().build()); stateMachines = handler.getWorkflowStateMachines(); QueryResult queryResult = diff --git a/temporal-sdk/src/test/java/io/temporal/internal/replay/ReplayWorkflowRunTaskHandlerCacheTests.java b/temporal-sdk/src/test/java/io/temporal/internal/replay/ReplayWorkflowRunTaskHandlerCacheTests.java index 76d408bb3..94138738a 100644 --- a/temporal-sdk/src/test/java/io/temporal/internal/replay/ReplayWorkflowRunTaskHandlerCacheTests.java +++ b/temporal-sdk/src/test/java/io/temporal/internal/replay/ReplayWorkflowRunTaskHandlerCacheTests.java @@ -36,6 +36,7 @@ import io.temporal.api.common.v1.WorkflowExecution; import io.temporal.api.history.v1.HistoryEvent; import io.temporal.api.query.v1.WorkflowQuery; +import io.temporal.api.workflowservice.v1.GetSystemInfoResponse; import io.temporal.api.workflowservice.v1.PollWorkflowTaskQueueResponse; import io.temporal.common.reporter.TestStatsReporter; import io.temporal.internal.statemachines.UpdateProtocolCallback; @@ -329,6 +330,7 @@ public WorkflowContext getWorkflowContext() { response, SingleWorkerOptions.newBuilder().build(), metricsScope, - (a, b, c) -> true); + (a, b, c) -> true, + GetSystemInfoResponse.Capabilities.newBuilder().build()); } } diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/activityTests/AsyncActivityRetryTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/activityTests/AsyncActivityRetryTest.java index a134bd6f1..0bae52863 100644 --- a/temporal-sdk/src/test/java/io/temporal/workflow/activityTests/AsyncActivityRetryTest.java +++ b/temporal-sdk/src/test/java/io/temporal/workflow/activityTests/AsyncActivityRetryTest.java @@ -70,7 +70,7 @@ public void testAsyncActivityRetry() { } @Test - public void testAsyncActivityRetry_replay() throws Exception { + public void testAsyncActivityRetryReplay() throws Exception { WorkflowReplayer.replayWorkflowExecutionFromResource( "testAsyncActivityRetryHistory.json", TestAsyncActivityRetry.class); } diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/childWorkflowTests/ChildWorkflowRetryTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/childWorkflowTests/ChildWorkflowRetryTest.java index b6385aac8..c4e932016 100644 --- a/temporal-sdk/src/test/java/io/temporal/workflow/childWorkflowTests/ChildWorkflowRetryTest.java +++ b/temporal-sdk/src/test/java/io/temporal/workflow/childWorkflowTests/ChildWorkflowRetryTest.java @@ -124,7 +124,7 @@ public void testChildWorkflowRetry() { * compatible with the client that supports the server side retry. */ @Test - public void testChildWorkflowRetry_replay() throws Exception { + public void testChildWorkflowRetryReplay() throws Exception { WorkflowReplayer.replayWorkflowExecutionFromResource( "testChildWorkflowRetryHistory.json", TestChildWorkflowRetryWorkflow.class); } diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/versionTests/GetVersionAfterScopeCancellationInMainWorkflowMethodTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/versionTests/GetVersionAfterScopeCancellationInMainWorkflowMethodTest.java index 02d4958bd..0f616271a 100644 --- a/temporal-sdk/src/test/java/io/temporal/workflow/versionTests/GetVersionAfterScopeCancellationInMainWorkflowMethodTest.java +++ b/temporal-sdk/src/test/java/io/temporal/workflow/versionTests/GetVersionAfterScopeCancellationInMainWorkflowMethodTest.java @@ -82,7 +82,7 @@ public void testGetVersionAndCancelTimer() { } @Test - public void testGetVersionAndCancelTimer_replay() throws Exception { + public void testGetVersionAndCancelTimerReplay() throws Exception { WorkflowReplayer.replayWorkflowExecutionFromResource( "get_version_after_scope_cancellation.json", testWorkflowRule.getWorker()); } diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/versionTests/GetVersionInSignalOnReplayTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/versionTests/GetVersionInSignalOnReplayTest.java index ed1dada6b..7bba4825f 100644 --- a/temporal-sdk/src/test/java/io/temporal/workflow/versionTests/GetVersionInSignalOnReplayTest.java +++ b/temporal-sdk/src/test/java/io/temporal/workflow/versionTests/GetVersionInSignalOnReplayTest.java @@ -26,6 +26,7 @@ import io.temporal.api.common.v1.WorkflowExecution; import io.temporal.client.WorkflowClient; import io.temporal.client.WorkflowStub; +import io.temporal.testing.WorkflowReplayer; import io.temporal.testing.internal.SDKTestWorkflowRule; import io.temporal.worker.WorkerOptions; import io.temporal.workflow.Workflow; @@ -65,6 +66,12 @@ public void testGetVersionInSignal() { assertEquals("[done]", result); } + @Test + public void testGetVersionInSignalReplay() throws Exception { + WorkflowReplayer.replayWorkflowExecutionFromResource( + "testGetVersionInSignalHistory.json", TestGetVersionInSignal.class); + } + /** The following test covers the scenario where getVersion call is performed inside a signal */ public static class TestGetVersionInSignal implements TestWorkflows.TestSignaledWorkflow { diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/versionTests/GetVersionMultithreadingTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/versionTests/GetVersionMultithreadingTest.java new file mode 100644 index 000000000..fe487fda2 --- /dev/null +++ b/temporal-sdk/src/test/java/io/temporal/workflow/versionTests/GetVersionMultithreadingTest.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2022 Temporal Technologies, Inc. All Rights Reserved. + * + * Copyright (C) 2012-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Modifications copyright (C) 2017 Uber Technologies, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this material except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.temporal.workflow.versionTests; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import io.temporal.testing.WorkflowReplayer; +import io.temporal.testing.internal.SDKTestOptions; +import io.temporal.testing.internal.SDKTestWorkflowRule; +import io.temporal.worker.WorkerOptions; +import io.temporal.workflow.Async; +import io.temporal.workflow.Workflow; +import io.temporal.workflow.shared.TestActivities.TestActivitiesImpl; +import io.temporal.workflow.shared.TestActivities.VariousTestActivities; +import io.temporal.workflow.shared.TestWorkflows.TestWorkflow1; +import io.temporal.workflow.unsafe.WorkflowUnsafe; +import java.time.Duration; +import org.junit.Rule; +import org.junit.Test; + +public class GetVersionMultithreadingTest { + + private static boolean hasReplayed; + + @Rule + public SDKTestWorkflowRule testWorkflowRule = + SDKTestWorkflowRule.newBuilder() + .setWorkflowTypes(TestGetVersionWorkflowImpl.class) + .setActivityImplementations(new TestActivitiesImpl()) + // Forcing a replay. Full history arrived from a normal queue causing a replay. + .setWorkerOptions( + WorkerOptions.newBuilder() + .setStickyQueueScheduleToStartTimeout(Duration.ZERO) + .build()) + .build(); + + @Test + public void testGetVersionDefaultMultithreading() { + TestWorkflow1 workflowStub = + testWorkflowRule.newWorkflowStubTimeoutOptions(TestWorkflow1.class); + String result = workflowStub.execute(testWorkflowRule.getTaskQueue()); + assertTrue(hasReplayed); + assertEquals("activity1", result); + } + + @Test + public void testGetVersionDefaultMultithreadingReplay() throws Exception { + WorkflowReplayer.replayWorkflowExecutionFromResource( + "testGetVersionDefaultMultithreadingHistory.json", TestGetVersionWorkflowImpl.class); + } + + public static class TestGetVersionWorkflowImpl implements TestWorkflow1 { + + @Override + public String execute(String taskQueue) { + VariousTestActivities testActivities = + Workflow.newActivityStub( + VariousTestActivities.class, + SDKTestOptions.newActivityOptionsForTaskQueue(taskQueue)); + + Async.procedure( + () -> { + Workflow.sleep(1000); + }); + + // Test adding a version check in replay code with an additional thread running. + if (WorkflowUnsafe.isReplaying()) { + hasReplayed = true; + int version = Workflow.getVersion("changeId", Workflow.DEFAULT_VERSION, 1); + assertEquals(version, Workflow.DEFAULT_VERSION); + } + String result = + "activity" + testActivities.activity1(1); // This is executed in non-replay mode. + return result; + } + } +} diff --git a/temporal-sdk/src/test/java/io/temporal/workflow/versionTests/GetVersionTest.java b/temporal-sdk/src/test/java/io/temporal/workflow/versionTests/GetVersionTest.java index 947ddb557..e59464faa 100644 --- a/temporal-sdk/src/test/java/io/temporal/workflow/versionTests/GetVersionTest.java +++ b/temporal-sdk/src/test/java/io/temporal/workflow/versionTests/GetVersionTest.java @@ -23,6 +23,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; +import io.temporal.testing.WorkflowReplayer; import io.temporal.testing.internal.SDKTestOptions; import io.temporal.testing.internal.SDKTestWorkflowRule; import io.temporal.testing.internal.TracingWorkerInterceptor; @@ -78,6 +79,12 @@ public void testGetVersion() { "activity customActivity1"); } + @Test + public void testGetVersionReplay() throws Exception { + WorkflowReplayer.replayWorkflowExecutionFromResource( + "testGetVersionHistory.json", TestGetVersionWorkflowImpl.class); + } + public static class TestGetVersionWorkflowImpl implements TestWorkflow1 { @Override diff --git a/temporal-sdk/src/test/resources/testGetVersionDefaultMultithreadingHistory.json b/temporal-sdk/src/test/resources/testGetVersionDefaultMultithreadingHistory.json new file mode 100644 index 000000000..02e319c15 --- /dev/null +++ b/temporal-sdk/src/test/resources/testGetVersionDefaultMultithreadingHistory.json @@ -0,0 +1,233 @@ +{ + "events": [ + { + "eventId": "1", + "eventTime": "2023-07-06T17:00:31.170759341Z", + "eventType": "WorkflowExecutionStarted", + "taskId": "2097152", + "workflowExecutionStartedEventAttributes": { + "workflowType": { + "name": "TestWorkflow1" + }, + "taskQueue": { + "name": "WorkflowTest-testGetVersionDefaultMultithreading-9d15660e-175f-4665-b93f-3266583002f5", + "kind": "Normal" + }, + "input": { + "payloads": [ + { + "metadata": { + "encoding": "anNvbi9wbGFpbg==" + }, + "data": "IldvcmtmbG93VGVzdC10ZXN0R2V0VmVyc2lvbkRlZmF1bHRNdWx0aXRocmVhZGluZy05ZDE1NjYwZS0xNzVmLTQ2NjUtYjkzZi0zMjY2NTgzMDAyZjUi" + } + ] + }, + "workflowExecutionTimeout": "0s", + "workflowRunTimeout": "200s", + "workflowTaskTimeout": "5s", + "originalExecutionRunId": "e88ef119-1fc1-4961-8cbc-e9dd609a18f7", + "identity": "12285@Quinn-Klassens-MacBook-Pro.local", + "firstExecutionRunId": "e88ef119-1fc1-4961-8cbc-e9dd609a18f7", + "attempt": 1, + "firstWorkflowTaskBackoff": "0s", + "header": { + + } + } + }, + { + "eventId": "2", + "eventTime": "2023-07-06T17:00:31.170785883Z", + "eventType": "WorkflowTaskScheduled", + "taskId": "2097153", + "workflowTaskScheduledEventAttributes": { + "taskQueue": { + "name": "WorkflowTest-testGetVersionDefaultMultithreading-9d15660e-175f-4665-b93f-3266583002f5", + "kind": "Normal" + }, + "startToCloseTimeout": "5s", + "attempt": 1 + } + }, + { + "eventId": "3", + "eventTime": "2023-07-06T17:00:31.180378758Z", + "eventType": "WorkflowTaskStarted", + "taskId": "2097159", + "workflowTaskStartedEventAttributes": { + "scheduledEventId": "2", + "identity": "12285@Quinn-Klassens-MacBook-Pro.local", + "requestId": "3362611b-d08b-410a-aeb7-97024c584a0e", + "historySizeBytes": "552" + } + }, + { + "eventId": "4", + "eventTime": "2023-07-06T17:00:31.505388258Z", + "eventType": "WorkflowTaskCompleted", + "taskId": "2097164", + "workflowTaskCompletedEventAttributes": { + "scheduledEventId": "2", + "startedEventId": "3", + "identity": "12285@Quinn-Klassens-MacBook-Pro.local", + "workerVersioningId": { + + }, + "sdkMetadata": { + "langUsedFlags": [ + 1 + ] + }, + "meteringMetadata": { + + } + } + }, + { + "eventId": "5", + "eventTime": "2023-07-06T17:00:31.505527341Z", + "eventType": "ActivityTaskScheduled", + "taskId": "2097165", + "activityTaskScheduledEventAttributes": { + "activityId": "b5a5ca00-175f-3dc6-a658-40ed82292c02", + "activityType": { + "name": "customActivity1" + }, + "taskQueue": { + "name": "WorkflowTest-testGetVersionDefaultMultithreading-9d15660e-175f-4665-b93f-3266583002f5", + "kind": "Normal" + }, + "header": { + + }, + "input": { + "payloads": [ + { + "metadata": { + "encoding": "anNvbi9wbGFpbg==" + }, + "data": "MQ==" + } + ] + }, + "scheduleToCloseTimeout": "5s", + "scheduleToStartTimeout": "5s", + "startToCloseTimeout": "5s", + "heartbeatTimeout": "5s", + "workflowTaskCompletedEventId": "4", + "retryPolicy": { + "initialInterval": "1s", + "backoffCoefficient": 2, + "maximumInterval": "100s" + } + } + }, + { + "eventId": "6", + "eventTime": "2023-07-06T17:00:31.505550966Z", + "eventType": "TimerStarted", + "taskId": "2097166", + "timerStartedEventAttributes": { + "timerId": "faa02a4d-20d9-3744-951b-3a6dd9c70f35", + "startToFireTimeout": "1s", + "workflowTaskCompletedEventId": "4" + } + }, + { + "eventId": "7", + "eventTime": "2023-07-06T17:00:31.505571466Z", + "eventType": "ActivityTaskStarted", + "taskId": "2097171", + "activityTaskStartedEventAttributes": { + "scheduledEventId": "5", + "identity": "12285@Quinn-Klassens-MacBook-Pro.local", + "requestId": "2e5770d3-b61c-451d-9a00-af3a3651df7d", + "attempt": 1 + } + }, + { + "eventId": "8", + "eventTime": "2023-07-06T17:00:31.542376841Z", + "eventType": "ActivityTaskCompleted", + "taskId": "2097172", + "activityTaskCompletedEventAttributes": { + "result": { + "payloads": [ + { + "metadata": { + "encoding": "anNvbi9wbGFpbg==" + }, + "data": "MQ==" + } + ] + }, + "scheduledEventId": "5", + "startedEventId": "7", + "identity": "12285@Quinn-Klassens-MacBook-Pro.local" + } + }, + { + "eventId": "9", + "eventTime": "2023-07-06T17:00:31.542381133Z", + "eventType": "WorkflowTaskScheduled", + "taskId": "2097173", + "workflowTaskScheduledEventAttributes": { + "taskQueue": { + "name": "WorkflowTest-testGetVersionDefaultMultithreading-9d15660e-175f-4665-b93f-3266583002f5", + "kind": "Normal" + }, + "startToCloseTimeout": "5s", + "attempt": 1 + } + }, + { + "eventId": "10", + "eventTime": "2023-07-06T17:00:31.554916550Z", + "eventType": "WorkflowTaskStarted", + "taskId": "2097176", + "workflowTaskStartedEventAttributes": { + "scheduledEventId": "9", + "identity": "12285@Quinn-Klassens-MacBook-Pro.local", + "requestId": "43f1c7ec-35a5-41c0-bc9a-101f23f2d4f8", + "historySizeBytes": "1399" + } + }, + { + "eventId": "11", + "eventTime": "2023-07-06T17:00:31.597299966Z", + "eventType": "WorkflowTaskCompleted", + "taskId": "2097180", + "workflowTaskCompletedEventAttributes": { + "scheduledEventId": "9", + "startedEventId": "10", + "identity": "12285@Quinn-Klassens-MacBook-Pro.local", + "workerVersioningId": { + + }, + "meteringMetadata": { + + } + } + }, + { + "eventId": "12", + "eventTime": "2023-07-06T17:00:31.597326300Z", + "eventType": "WorkflowExecutionCompleted", + "taskId": "2097181", + "workflowExecutionCompletedEventAttributes": { + "result": { + "payloads": [ + { + "metadata": { + "encoding": "anNvbi9wbGFpbg==" + }, + "data": "ImFjdGl2aXR5MSI=" + } + ] + }, + "workflowTaskCompletedEventId": "11" + } + } + ] +} \ No newline at end of file diff --git a/temporal-sdk/src/test/resources/testGetVersionHistory.json b/temporal-sdk/src/test/resources/testGetVersionHistory.json new file mode 100644 index 000000000..842e8860b --- /dev/null +++ b/temporal-sdk/src/test/resources/testGetVersionHistory.json @@ -0,0 +1,669 @@ +{ + "events": [ + { + "eventId": "1", + "eventTime": "2023-07-06T16:51:21.316623462Z", + "eventType": "WorkflowExecutionStarted", + "taskId": "2097153", + "workflowExecutionStartedEventAttributes": { + "workflowType": { + "name": "TestWorkflow1" + }, + "taskQueue": { + "name": "WorkflowTest-testGetVersion-6512a843-5d1c-44c2-929e-57c452996e47", + "kind": "Normal" + }, + "input": { + "payloads": [ + { + "metadata": { + "encoding": "anNvbi9wbGFpbg==" + }, + "data": "IldvcmtmbG93VGVzdC10ZXN0R2V0VmVyc2lvbi02NTEyYTg0My01ZDFjLTQ0YzItOTI5ZS01N2M0NTI5OTZlNDci" + } + ] + }, + "workflowExecutionTimeout": "0s", + "workflowRunTimeout": "200s", + "workflowTaskTimeout": "5s", + "originalExecutionRunId": "6bb1e0c6-66d3-456f-a7cc-1e0ff2e76e6c", + "identity": "10490@Quinn-Klassens-MacBook-Pro.local", + "firstExecutionRunId": "6bb1e0c6-66d3-456f-a7cc-1e0ff2e76e6c", + "attempt": 1, + "firstWorkflowTaskBackoff": "0s", + "header": { + + } + } + }, + { + "eventId": "2", + "eventTime": "2023-07-06T16:51:21.316647837Z", + "eventType": "WorkflowTaskScheduled", + "taskId": "2097154", + "workflowTaskScheduledEventAttributes": { + "taskQueue": { + "name": "WorkflowTest-testGetVersion-6512a843-5d1c-44c2-929e-57c452996e47", + "kind": "Normal" + }, + "startToCloseTimeout": "5s", + "attempt": 1 + } + }, + { + "eventId": "3", + "eventTime": "2023-07-06T16:51:21.332044503Z", + "eventType": "WorkflowTaskStarted", + "taskId": "2097160", + "workflowTaskStartedEventAttributes": { + "scheduledEventId": "2", + "identity": "10490@Quinn-Klassens-MacBook-Pro.local", + "requestId": "f9d955b7-51de-4ed8-8845-0bfbab0a8735", + "historySizeBytes": "491" + } + }, + { + "eventId": "4", + "eventTime": "2023-07-06T16:51:21.632728462Z", + "eventType": "WorkflowTaskCompleted", + "taskId": "2097165", + "workflowTaskCompletedEventAttributes": { + "scheduledEventId": "2", + "startedEventId": "3", + "identity": "10490@Quinn-Klassens-MacBook-Pro.local", + "workerVersioningId": { + + }, + "sdkMetadata": { + "langUsedFlags": [ + 1 + ] + }, + "meteringMetadata": { + + } + } + }, + { + "eventId": "5", + "eventTime": "2023-07-06T16:51:21.632765962Z", + "eventType": "MarkerRecorded", + "taskId": "2097166", + "markerRecordedEventAttributes": { + "markerName": "Version", + "details": { + "changeId": { + "payloads": [ + { + "metadata": { + "encoding": "anNvbi9wbGFpbg==" + }, + "data": "InRlc3RfY2hhbmdlIg==" + } + ] + }, + "version": { + "payloads": [ + { + "metadata": { + "encoding": "anNvbi9wbGFpbg==" + }, + "data": "MQ==" + } + ] + } + }, + "workflowTaskCompletedEventId": "4" + } + }, + { + "eventId": "6", + "eventTime": "2023-07-06T16:51:21.632777879Z", + "eventType": "ActivityTaskScheduled", + "taskId": "2097167", + "activityTaskScheduledEventAttributes": { + "activityId": "94114672-be89-3741-8319-f7ce07ad93ec", + "activityType": { + "name": "Activity2" + }, + "taskQueue": { + "name": "WorkflowTest-testGetVersion-6512a843-5d1c-44c2-929e-57c452996e47", + "kind": "Normal" + }, + "header": { + + }, + "input": { + "payloads": [ + { + "metadata": { + "encoding": "anNvbi9wbGFpbg==" + }, + "data": "ImFjdGl2aXR5MiI=" + }, + { + "metadata": { + "encoding": "anNvbi9wbGFpbg==" + }, + "data": "Mg==" + } + ] + }, + "scheduleToCloseTimeout": "5s", + "scheduleToStartTimeout": "5s", + "startToCloseTimeout": "5s", + "heartbeatTimeout": "5s", + "workflowTaskCompletedEventId": "4", + "retryPolicy": { + "initialInterval": "1s", + "backoffCoefficient": 2, + "maximumInterval": "100s" + } + } + }, + { + "eventId": "7", + "eventTime": "2023-07-06T16:51:21.632791045Z", + "eventType": "ActivityTaskStarted", + "taskId": "2097171", + "activityTaskStartedEventAttributes": { + "scheduledEventId": "6", + "identity": "10490@Quinn-Klassens-MacBook-Pro.local", + "requestId": "0dcdc159-c030-4421-894b-60fc7d6f7390", + "attempt": 1 + } + }, + { + "eventId": "8", + "eventTime": "2023-07-06T16:51:21.658544545Z", + "eventType": "ActivityTaskCompleted", + "taskId": "2097172", + "activityTaskCompletedEventAttributes": { + "result": { + "payloads": [ + { + "metadata": { + "encoding": "anNvbi9wbGFpbg==" + }, + "data": "ImFjdGl2aXR5MjIi" + } + ] + }, + "scheduledEventId": "6", + "startedEventId": "7", + "identity": "10490@Quinn-Klassens-MacBook-Pro.local" + } + }, + { + "eventId": "9", + "eventTime": "2023-07-06T16:51:21.658549087Z", + "eventType": "WorkflowTaskScheduled", + "taskId": "2097173", + "workflowTaskScheduledEventAttributes": { + "taskQueue": { + "name": "WorkflowTest-testGetVersion-6512a843-5d1c-44c2-929e-57c452996e47", + "kind": "Normal" + }, + "startToCloseTimeout": "5s", + "attempt": 1 + } + }, + { + "eventId": "10", + "eventTime": "2023-07-06T16:51:21.667116504Z", + "eventType": "WorkflowTaskStarted", + "taskId": "2097176", + "workflowTaskStartedEventAttributes": { + "scheduledEventId": "9", + "identity": "10490@Quinn-Klassens-MacBook-Pro.local", + "requestId": "b4544f62-bbe8-49e4-b9ba-ca22538a99c7", + "historySizeBytes": "1406" + } + }, + { + "eventId": "11", + "eventTime": "2023-07-06T16:51:21.708022920Z", + "eventType": "WorkflowTaskCompleted", + "taskId": "2097181", + "workflowTaskCompletedEventAttributes": { + "scheduledEventId": "9", + "startedEventId": "10", + "identity": "10490@Quinn-Klassens-MacBook-Pro.local", + "workerVersioningId": { + + }, + "meteringMetadata": { + + } + } + }, + { + "eventId": "12", + "eventTime": "2023-07-06T16:51:21.708060045Z", + "eventType": "ActivityTaskScheduled", + "taskId": "2097182", + "activityTaskScheduledEventAttributes": { + "activityId": "89fbd644-3039-3cf4-93c4-bb60abbfc93a", + "activityType": { + "name": "customActivity1" + }, + "taskQueue": { + "name": "WorkflowTest-testGetVersion-6512a843-5d1c-44c2-929e-57c452996e47", + "kind": "Normal" + }, + "header": { + + }, + "input": { + "payloads": [ + { + "metadata": { + "encoding": "anNvbi9wbGFpbg==" + }, + "data": "MQ==" + } + ] + }, + "scheduleToCloseTimeout": "5s", + "scheduleToStartTimeout": "5s", + "startToCloseTimeout": "5s", + "heartbeatTimeout": "5s", + "workflowTaskCompletedEventId": "11", + "retryPolicy": { + "initialInterval": "1s", + "backoffCoefficient": 2, + "maximumInterval": "100s" + } + } + }, + { + "eventId": "13", + "eventTime": "2023-07-06T16:51:21.708071879Z", + "eventType": "ActivityTaskStarted", + "taskId": "2097186", + "activityTaskStartedEventAttributes": { + "scheduledEventId": "12", + "identity": "10490@Quinn-Klassens-MacBook-Pro.local", + "requestId": "a5079544-88b5-448a-9bb4-75ed7b3c1627", + "attempt": 1 + } + }, + { + "eventId": "14", + "eventTime": "2023-07-06T16:51:21.719172170Z", + "eventType": "ActivityTaskCompleted", + "taskId": "2097187", + "activityTaskCompletedEventAttributes": { + "result": { + "payloads": [ + { + "metadata": { + "encoding": "anNvbi9wbGFpbg==" + }, + "data": "MQ==" + } + ] + }, + "scheduledEventId": "12", + "startedEventId": "13", + "identity": "10490@Quinn-Klassens-MacBook-Pro.local" + } + }, + { + "eventId": "15", + "eventTime": "2023-07-06T16:51:21.719176129Z", + "eventType": "WorkflowTaskScheduled", + "taskId": "2097188", + "workflowTaskScheduledEventAttributes": { + "taskQueue": { + "name": "WorkflowTest-testGetVersion-6512a843-5d1c-44c2-929e-57c452996e47", + "kind": "Normal" + }, + "startToCloseTimeout": "5s", + "attempt": 1 + } + }, + { + "eventId": "16", + "eventTime": "2023-07-06T16:51:21.730094837Z", + "eventType": "WorkflowTaskStarted", + "taskId": "2097191", + "workflowTaskStartedEventAttributes": { + "scheduledEventId": "15", + "identity": "10490@Quinn-Klassens-MacBook-Pro.local", + "requestId": "1b641837-c31d-4003-a8da-4f3a0a33ef5e", + "historySizeBytes": "2135" + } + }, + { + "eventId": "17", + "eventTime": "2023-07-06T16:51:21.753424212Z", + "eventType": "WorkflowTaskCompleted", + "taskId": "2097196", + "workflowTaskCompletedEventAttributes": { + "scheduledEventId": "15", + "startedEventId": "16", + "identity": "10490@Quinn-Klassens-MacBook-Pro.local", + "workerVersioningId": { + + }, + "meteringMetadata": { + + } + } + }, + { + "eventId": "18", + "eventTime": "2023-07-06T16:51:21.753455045Z", + "eventType": "ActivityTaskScheduled", + "taskId": "2097197", + "activityTaskScheduledEventAttributes": { + "activityId": "bd1401f4-ea1f-39bb-8792-6ac6ac9c0a03", + "activityType": { + "name": "customActivity1" + }, + "taskQueue": { + "name": "WorkflowTest-testGetVersion-6512a843-5d1c-44c2-929e-57c452996e47", + "kind": "Normal" + }, + "header": { + + }, + "input": { + "payloads": [ + { + "metadata": { + "encoding": "anNvbi9wbGFpbg==" + }, + "data": "MQ==" + } + ] + }, + "scheduleToCloseTimeout": "5s", + "scheduleToStartTimeout": "5s", + "startToCloseTimeout": "5s", + "heartbeatTimeout": "5s", + "workflowTaskCompletedEventId": "17", + "retryPolicy": { + "initialInterval": "1s", + "backoffCoefficient": 2, + "maximumInterval": "100s" + } + } + }, + { + "eventId": "19", + "eventTime": "2023-07-06T16:51:21.753464629Z", + "eventType": "ActivityTaskStarted", + "taskId": "2097201", + "activityTaskStartedEventAttributes": { + "scheduledEventId": "18", + "identity": "10490@Quinn-Klassens-MacBook-Pro.local", + "requestId": "7e5c914d-6a8b-433d-b496-e5120884a484", + "attempt": 1 + } + }, + { + "eventId": "20", + "eventTime": "2023-07-06T16:51:21.769053212Z", + "eventType": "ActivityTaskCompleted", + "taskId": "2097202", + "activityTaskCompletedEventAttributes": { + "result": { + "payloads": [ + { + "metadata": { + "encoding": "anNvbi9wbGFpbg==" + }, + "data": "MQ==" + } + ] + }, + "scheduledEventId": "18", + "startedEventId": "19", + "identity": "10490@Quinn-Klassens-MacBook-Pro.local" + } + }, + { + "eventId": "21", + "eventTime": "2023-07-06T16:51:21.769057462Z", + "eventType": "WorkflowTaskScheduled", + "taskId": "2097203", + "workflowTaskScheduledEventAttributes": { + "taskQueue": { + "name": "WorkflowTest-testGetVersion-6512a843-5d1c-44c2-929e-57c452996e47", + "kind": "Normal" + }, + "startToCloseTimeout": "5s", + "attempt": 1 + } + }, + { + "eventId": "22", + "eventTime": "2023-07-06T16:51:21.778384420Z", + "eventType": "WorkflowTaskStarted", + "taskId": "2097206", + "workflowTaskStartedEventAttributes": { + "scheduledEventId": "21", + "identity": "10490@Quinn-Klassens-MacBook-Pro.local", + "requestId": "d6b9ac4b-da65-4f1e-9ba8-4ceba1da6b74", + "historySizeBytes": "2864" + } + }, + { + "eventId": "23", + "eventTime": "2023-07-06T16:51:21.810635587Z", + "eventType": "WorkflowTaskCompleted", + "taskId": "2097210", + "workflowTaskCompletedEventAttributes": { + "scheduledEventId": "21", + "startedEventId": "22", + "identity": "10490@Quinn-Klassens-MacBook-Pro.local", + "workerVersioningId": { + + }, + "meteringMetadata": { + + } + } + }, + { + "eventId": "24", + "eventTime": "2023-07-06T16:51:21.810657254Z", + "eventType": "TimerStarted", + "taskId": "2097211", + "timerStartedEventAttributes": { + "timerId": "c9ca92f1-4982-36aa-93c5-5dcc5e1fd6b0", + "startToFireTimeout": "1s", + "workflowTaskCompletedEventId": "23" + } + }, + { + "eventId": "25", + "eventTime": "2023-07-06T16:51:22.817142462Z", + "eventType": "TimerFired", + "taskId": "2097215", + "timerFiredEventAttributes": { + "timerId": "c9ca92f1-4982-36aa-93c5-5dcc5e1fd6b0", + "startedEventId": "24" + } + }, + { + "eventId": "26", + "eventTime": "2023-07-06T16:51:22.817159921Z", + "eventType": "WorkflowTaskScheduled", + "taskId": "2097216", + "workflowTaskScheduledEventAttributes": { + "taskQueue": { + "name": "WorkflowTest-testGetVersion-6512a843-5d1c-44c2-929e-57c452996e47", + "kind": "Normal" + }, + "startToCloseTimeout": "5s", + "attempt": 1 + } + }, + { + "eventId": "27", + "eventTime": "2023-07-06T16:51:22.837294254Z", + "eventType": "WorkflowTaskStarted", + "taskId": "2097219", + "workflowTaskStartedEventAttributes": { + "scheduledEventId": "26", + "identity": "10490@Quinn-Klassens-MacBook-Pro.local", + "requestId": "316e5b90-d3a9-4028-8304-0e146d9cabda", + "historySizeBytes": "3292" + } + }, + { + "eventId": "28", + "eventTime": "2023-07-06T16:51:22.875753046Z", + "eventType": "WorkflowTaskCompleted", + "taskId": "2097224", + "workflowTaskCompletedEventAttributes": { + "scheduledEventId": "26", + "startedEventId": "27", + "identity": "10490@Quinn-Klassens-MacBook-Pro.local", + "workerVersioningId": { + + }, + "meteringMetadata": { + + } + } + }, + { + "eventId": "29", + "eventTime": "2023-07-06T16:51:22.875783504Z", + "eventType": "ActivityTaskScheduled", + "taskId": "2097225", + "activityTaskScheduledEventAttributes": { + "activityId": "2252d37e-ea19-31ce-8079-fbf232f79a3d", + "activityType": { + "name": "customActivity1" + }, + "taskQueue": { + "name": "WorkflowTest-testGetVersion-6512a843-5d1c-44c2-929e-57c452996e47", + "kind": "Normal" + }, + "header": { + + }, + "input": { + "payloads": [ + { + "metadata": { + "encoding": "anNvbi9wbGFpbg==" + }, + "data": "MQ==" + } + ] + }, + "scheduleToCloseTimeout": "5s", + "scheduleToStartTimeout": "5s", + "startToCloseTimeout": "5s", + "heartbeatTimeout": "5s", + "workflowTaskCompletedEventId": "28", + "retryPolicy": { + "initialInterval": "1s", + "backoffCoefficient": 2, + "maximumInterval": "100s" + } + } + }, + { + "eventId": "30", + "eventTime": "2023-07-06T16:51:22.875793921Z", + "eventType": "ActivityTaskStarted", + "taskId": "2097229", + "activityTaskStartedEventAttributes": { + "scheduledEventId": "29", + "identity": "10490@Quinn-Klassens-MacBook-Pro.local", + "requestId": "b7c0f9a6-8550-457c-8c86-5c87c324eff4", + "attempt": 1 + } + }, + { + "eventId": "31", + "eventTime": "2023-07-06T16:51:22.889643004Z", + "eventType": "ActivityTaskCompleted", + "taskId": "2097230", + "activityTaskCompletedEventAttributes": { + "result": { + "payloads": [ + { + "metadata": { + "encoding": "anNvbi9wbGFpbg==" + }, + "data": "MQ==" + } + ] + }, + "scheduledEventId": "29", + "startedEventId": "30", + "identity": "10490@Quinn-Klassens-MacBook-Pro.local" + } + }, + { + "eventId": "32", + "eventTime": "2023-07-06T16:51:22.889647879Z", + "eventType": "WorkflowTaskScheduled", + "taskId": "2097231", + "workflowTaskScheduledEventAttributes": { + "taskQueue": { + "name": "WorkflowTest-testGetVersion-6512a843-5d1c-44c2-929e-57c452996e47", + "kind": "Normal" + }, + "startToCloseTimeout": "5s", + "attempt": 1 + } + }, + { + "eventId": "33", + "eventTime": "2023-07-06T16:51:22.897281504Z", + "eventType": "WorkflowTaskStarted", + "taskId": "2097234", + "workflowTaskStartedEventAttributes": { + "scheduledEventId": "32", + "identity": "10490@Quinn-Klassens-MacBook-Pro.local", + "requestId": "75388218-1bca-4820-832c-32623b0c96c2", + "historySizeBytes": "4021" + } + }, + { + "eventId": "34", + "eventTime": "2023-07-06T16:51:22.929242004Z", + "eventType": "WorkflowTaskCompleted", + "taskId": "2097238", + "workflowTaskCompletedEventAttributes": { + "scheduledEventId": "32", + "startedEventId": "33", + "identity": "10490@Quinn-Klassens-MacBook-Pro.local", + "workerVersioningId": { + + }, + "meteringMetadata": { + + } + } + }, + { + "eventId": "35", + "eventTime": "2023-07-06T16:51:22.929265546Z", + "eventType": "WorkflowExecutionCompleted", + "taskId": "2097239", + "workflowExecutionCompletedEventAttributes": { + "result": { + "payloads": [ + { + "metadata": { + "encoding": "anNvbi9wbGFpbg==" + }, + "data": "ImFjdGl2aXR5MjJhY3Rpdml0eTFhY3Rpdml0eTFhY3Rpdml0eTEi" + } + ] + }, + "workflowTaskCompletedEventId": "34" + } + } + ] +} \ No newline at end of file diff --git a/temporal-sdk/src/test/resources/testGetVersionInSignalHistory.json b/temporal-sdk/src/test/resources/testGetVersionInSignalHistory.json new file mode 100644 index 000000000..ac0979767 --- /dev/null +++ b/temporal-sdk/src/test/resources/testGetVersionInSignalHistory.json @@ -0,0 +1,256 @@ +{ + "events": [ + { + "eventId": "1", + "eventTime": "2023-07-06T17:24:54.736148002Z", + "eventType": "WorkflowExecutionStarted", + "taskId": "2097187", + "workflowExecutionStartedEventAttributes": { + "workflowType": { + "name": "TestSignaledWorkflow" + }, + "taskQueue": { + "name": "WorkflowTest-testGetVersionInSignal-35db2536-9b0e-4ab7-84c5-70abc3470f49", + "kind": "Normal" + }, + "workflowExecutionTimeout": "0s", + "workflowRunTimeout": "200s", + "workflowTaskTimeout": "5s", + "originalExecutionRunId": "0f234e31-6386-44bf-b033-55fcf5c0954e", + "identity": "14005@Quinn-Klassens-MacBook-Pro.local", + "firstExecutionRunId": "0f234e31-6386-44bf-b033-55fcf5c0954e", + "attempt": 1, + "firstWorkflowTaskBackoff": "0s", + "header": { + + } + } + }, + { + "eventId": "2", + "eventTime": "2023-07-06T17:24:54.736175669Z", + "eventType": "WorkflowTaskScheduled", + "taskId": "2097188", + "workflowTaskScheduledEventAttributes": { + "taskQueue": { + "name": "WorkflowTest-testGetVersionInSignal-35db2536-9b0e-4ab7-84c5-70abc3470f49", + "kind": "Normal" + }, + "startToCloseTimeout": "5s", + "attempt": 1 + } + }, + { + "eventId": "3", + "eventTime": "2023-07-06T17:24:54.748504919Z", + "eventType": "WorkflowTaskStarted", + "taskId": "2097194", + "workflowTaskStartedEventAttributes": { + "scheduledEventId": "2", + "identity": "14005@Quinn-Klassens-MacBook-Pro.local", + "requestId": "da3d3e08-075f-43b2-b93a-4ed10ce5c11e", + "historySizeBytes": "418" + } + }, + { + "eventId": "4", + "eventTime": "2023-07-06T17:24:55.029474669Z", + "eventType": "WorkflowTaskCompleted", + "taskId": "2097198", + "workflowTaskCompletedEventAttributes": { + "scheduledEventId": "2", + "startedEventId": "3", + "identity": "14005@Quinn-Klassens-MacBook-Pro.local", + "workerVersioningId": { + + }, + "sdkMetadata": { + "langUsedFlags": [ + 1 + ] + }, + "meteringMetadata": { + + } + } + }, + { + "eventId": "5", + "eventTime": "2023-07-06T17:24:55.029494252Z", + "eventType": "TimerStarted", + "taskId": "2097199", + "timerStartedEventAttributes": { + "timerId": "598597dd-3b90-3143-a9e4-8e92623d3929", + "startToFireTimeout": "5s", + "workflowTaskCompletedEventId": "4" + } + }, + { + "eventId": "6", + "eventTime": "2023-07-06T17:24:55.093634461Z", + "eventType": "WorkflowExecutionSignaled", + "taskId": "2097203", + "workflowExecutionSignaledEventAttributes": { + "signalName": "testSignal", + "input": { + "payloads": [ + { + "metadata": { + "encoding": "anNvbi9wbGFpbg==" + }, + "data": "ImRvbmUi" + } + ] + }, + "identity": "14005@Quinn-Klassens-MacBook-Pro.local" + } + }, + { + "eventId": "7", + "eventTime": "2023-07-06T17:24:55.093638002Z", + "eventType": "WorkflowTaskScheduled", + "taskId": "2097204", + "workflowTaskScheduledEventAttributes": { + "taskQueue": { + "name": "WorkflowTest-testGetVersionInSignal-35db2536-9b0e-4ab7-84c5-70abc3470f49", + "kind": "Normal" + }, + "startToCloseTimeout": "5s", + "attempt": 1 + } + }, + { + "eventId": "8", + "eventTime": "2023-07-06T17:24:55.100958294Z", + "eventType": "WorkflowTaskStarted", + "taskId": "2097207", + "workflowTaskStartedEventAttributes": { + "scheduledEventId": "7", + "identity": "14005@Quinn-Klassens-MacBook-Pro.local", + "requestId": "ba03af0b-a98f-4535-b434-0771574b7fa2", + "historySizeBytes": "903" + } + }, + { + "eventId": "9", + "eventTime": "2023-07-06T17:24:55.137837086Z", + "eventType": "WorkflowTaskCompleted", + "taskId": "2097211", + "workflowTaskCompletedEventAttributes": { + "scheduledEventId": "7", + "startedEventId": "8", + "identity": "14005@Quinn-Klassens-MacBook-Pro.local", + "workerVersioningId": { + + }, + "meteringMetadata": { + + } + } + }, + { + "eventId": "10", + "eventTime": "2023-07-06T17:24:55.137857711Z", + "eventType": "MarkerRecorded", + "taskId": "2097212", + "markerRecordedEventAttributes": { + "markerName": "Version", + "details": { + "changeId": { + "payloads": [ + { + "metadata": { + "encoding": "anNvbi9wbGFpbg==" + }, + "data": "InNvbWUtaWQi" + } + ] + }, + "version": { + "payloads": [ + { + "metadata": { + "encoding": "anNvbi9wbGFpbg==" + }, + "data": "Mg==" + } + ] + } + }, + "workflowTaskCompletedEventId": "9" + } + }, + { + "eventId": "11", + "eventTime": "2023-07-06T17:25:00.031737088Z", + "eventType": "TimerFired", + "taskId": "2097215", + "timerFiredEventAttributes": { + "timerId": "598597dd-3b90-3143-a9e4-8e92623d3929", + "startedEventId": "5" + } + }, + { + "eventId": "12", + "eventTime": "2023-07-06T17:25:00.031753338Z", + "eventType": "WorkflowTaskScheduled", + "taskId": "2097216", + "workflowTaskScheduledEventAttributes": { + "taskQueue": { + "name": "WorkflowTest-testGetVersionInSignal-35db2536-9b0e-4ab7-84c5-70abc3470f49", + "kind": "Normal" + }, + "startToCloseTimeout": "5s", + "attempt": 1 + } + }, + { + "eventId": "13", + "eventTime": "2023-07-06T17:25:00.061174046Z", + "eventType": "WorkflowTaskStarted", + "taskId": "2097219", + "workflowTaskStartedEventAttributes": { + "scheduledEventId": "12", + "identity": "14005@Quinn-Klassens-MacBook-Pro.local", + "requestId": "ee26faa9-f2f7-421f-9e34-f5e93a51d513", + "historySizeBytes": "1395" + } + }, + { + "eventId": "14", + "eventTime": "2023-07-06T17:25:00.107807921Z", + "eventType": "WorkflowTaskCompleted", + "taskId": "2097223", + "workflowTaskCompletedEventAttributes": { + "scheduledEventId": "12", + "startedEventId": "13", + "identity": "14005@Quinn-Klassens-MacBook-Pro.local", + "workerVersioningId": { + + }, + "meteringMetadata": { + + } + } + }, + { + "eventId": "15", + "eventTime": "2023-07-06T17:25:00.107836046Z", + "eventType": "WorkflowExecutionCompleted", + "taskId": "2097224", + "workflowExecutionCompletedEventAttributes": { + "result": { + "payloads": [ + { + "metadata": { + "encoding": "anNvbi9wbGFpbg==" + }, + "data": "Iltkb25lXSI=" + } + ] + }, + "workflowTaskCompletedEventId": "14" + } + } + ] +} \ No newline at end of file diff --git a/temporal-testing/src/main/java/io/temporal/internal/sync/DummySyncWorkflowContext.java b/temporal-testing/src/main/java/io/temporal/internal/sync/DummySyncWorkflowContext.java index e8c222a17..b31245004 100644 --- a/temporal-testing/src/main/java/io/temporal/internal/sync/DummySyncWorkflowContext.java +++ b/temporal-testing/src/main/java/io/temporal/internal/sync/DummySyncWorkflowContext.java @@ -32,6 +32,7 @@ import io.temporal.api.failure.v1.Failure; import io.temporal.common.converter.DefaultDataConverter; import io.temporal.failure.CanceledFailure; +import io.temporal.internal.common.SdkFlag; import io.temporal.internal.replay.ReplayWorkflowContext; import io.temporal.internal.statemachines.ExecuteActivityParameters; import io.temporal.internal.statemachines.ExecuteLocalActivityParameters; @@ -273,7 +274,7 @@ public boolean isReplaying() { } @Override - public void getVersion( + public boolean getVersion( String changeId, int minSupported, int maxSupported, @@ -306,6 +307,11 @@ public void upsertSearchAttributes(@Nonnull SearchAttributes searchAttributes) { throw new UnsupportedOperationException("not implemented"); } + @Override + public boolean tryUseSdkFlag(SdkFlag flag) { + return false; + } + @Override public int getAttempt() { return 1;