1919import io .dapr .durabletask .implementation .protobuf .OrchestratorService .ScheduleTaskAction .Builder ;
2020import io .dapr .durabletask .interruption .ContinueAsNewInterruption ;
2121import io .dapr .durabletask .interruption .OrchestratorBlockedException ;
22+ import io .dapr .durabletask .orchestration .TaskOrchestrationFactories ;
23+ import io .dapr .durabletask .orchestration .TaskOrchestrationFactory ;
24+ import io .dapr .durabletask .orchestration .exception .VersionNotRegisteredException ;
2225import io .dapr .durabletask .util .UuidGenerator ;
26+ import io .opentelemetry .api .internal .StringUtils ;
2327
2428import javax .annotation .Nullable ;
2529import java .time .Duration ;
4751final class TaskOrchestrationExecutor {
4852
4953 private static final String EMPTY_STRING = "" ;
50- private final HashMap < String , TaskOrchestrationFactory > orchestrationFactories ;
54+ private final TaskOrchestrationFactories orchestrationFactories ;
5155 private final DataConverter dataConverter ;
5256 private final Logger logger ;
5357 private final Duration maximumTimerInterval ;
5458 private final String appId ;
5559
5660 public TaskOrchestrationExecutor (
57- HashMap < String , TaskOrchestrationFactory > orchestrationFactories ,
61+ TaskOrchestrationFactories orchestrationFactories ,
5862 DataConverter dataConverter ,
5963 Duration maximumTimerInterval ,
6064 Logger logger ,
@@ -79,6 +83,9 @@ public TaskOrchestratorResult execute(List<OrchestratorService.HistoryEvent> pas
7983 }
8084 completed = true ;
8185 logger .finest ("The orchestrator execution completed normally" );
86+ } catch (VersionNotRegisteredException versionNotRegisteredException ) {
87+ logger .warning ("The orchestrator version is not registered: " + versionNotRegisteredException .toString ());
88+ context .setVersionNotRegistered ();
8289 } catch (OrchestratorBlockedException orchestratorBlockedException ) {
8390 logger .fine ("The orchestrator has yielded and will await for new events." );
8491 } catch (ContinueAsNewInterruption continueAsNewInterruption ) {
@@ -87,7 +94,7 @@ public TaskOrchestratorResult execute(List<OrchestratorService.HistoryEvent> pas
8794 } catch (Exception e ) {
8895 // The orchestrator threw an unhandled exception - fail it
8996 // TODO: What's the right way to log this?
90- logger .warning ("The orchestrator failed with an unhandled exception: " + e . toString () );
97+ logger .warning ("The orchestrator failed with an unhandled exception: " + e );
9198 context .fail (new FailureDetails (e ));
9299 }
93100
@@ -97,12 +104,16 @@ public TaskOrchestratorResult execute(List<OrchestratorService.HistoryEvent> pas
97104 context .complete (null );
98105 }
99106
100- return new TaskOrchestratorResult (context .pendingActions .values (), context .getCustomStatus ());
107+ return new TaskOrchestratorResult (context .pendingActions .values (),
108+ context .getCustomStatus (),
109+ context .version ,
110+ context .encounteredPatches );
101111 }
102112
103113 private class ContextImplTask implements TaskOrchestrationContext {
104114
105115 private String orchestratorName ;
116+ private final List <String > encounteredPatches = new ArrayList <>();
106117 private String rawInput ;
107118 private String instanceId ;
108119 private Instant currentInstant ;
@@ -127,6 +138,11 @@ private class ContextImplTask implements TaskOrchestrationContext {
127138 private Object continuedAsNewInput ;
128139 private boolean preserveUnprocessedEvents ;
129140 private Object customStatus ;
141+ private final Map <String , Boolean > appliedPatches = new HashMap <>();
142+ private final Map <String , Boolean > historyPatches = new HashMap <>();
143+
144+ private OrchestratorService .OrchestrationVersion orchestratorStartedVersion ;
145+ private String version ;
130146
131147 public ContextImplTask (List <OrchestratorService .HistoryEvent > pastEvents ,
132148 List <OrchestratorService .HistoryEvent > newEvents ) {
@@ -144,6 +160,7 @@ private void setName(String name) {
144160 this .orchestratorName = name ;
145161 }
146162
163+
147164 private void setInput (String rawInput ) {
148165 this .rawInput = rawInput ;
149166 }
@@ -363,6 +380,34 @@ public <V> Task<V> callActivity(
363380 return this .createAppropriateTask (taskFactory , options );
364381 }
365382
383+ @ Override
384+ public boolean isPatched (String patchName ) {
385+ var isPatched = this .checkPatch (patchName );
386+ if (isPatched ) {
387+ this .encounteredPatches .add (patchName );
388+ }
389+
390+ return isPatched ;
391+ }
392+
393+ public boolean checkPatch (String patchName ) {
394+ if (this .appliedPatches .containsKey (patchName )) {
395+ return this .appliedPatches .get (patchName );
396+ }
397+
398+ if (this .historyPatches .containsKey (patchName )) {
399+ this .appliedPatches .put (patchName , true );
400+ return true ;
401+ }
402+
403+ if (this .isReplaying ) {
404+ this .appliedPatches .put (patchName , false );
405+ return false ;
406+ }
407+ this .appliedPatches .put (patchName , true );
408+ return true ;
409+ }
410+
366411 @ Override
367412 public void continueAsNew (Object input , boolean preserveUnprocessedEvents ) {
368413 Helpers .throwIfOrchestratorComplete (this .isComplete );
@@ -924,6 +969,7 @@ private void processEvent(OrchestratorService.HistoryEvent e) {
924969 case ORCHESTRATORSTARTED :
925970 Instant instant = DataConverter .getInstantFromTimestamp (e .getTimestamp ());
926971 this .setCurrentInstant (instant );
972+ this .orchestratorStartedVersion = e .getOrchestratorStarted ().getVersion ();
927973 this .logger .fine (() -> this .instanceId + ": Workflow orchestrator started" );
928974 break ;
929975 case ORCHESTRATORCOMPLETED :
@@ -938,18 +984,32 @@ private void processEvent(OrchestratorService.HistoryEvent e) {
938984 this .logger .fine (() -> this .instanceId + ": Workflow execution started" );
939985 this .setAppId (e .getRouter ().getSourceAppID ());
940986
987+ if (this .orchestratorStartedVersion != null
988+ && this .orchestratorStartedVersion .getPatchesCount () > 0 ) {
989+ for (var patch : this .orchestratorStartedVersion .getPatchesList ()) {
990+ this .historyPatches .put (patch , true );
991+ }
992+ }
993+
994+ var versionName = "" ;
995+ if (this .orchestratorStartedVersion != null && !StringUtils .isNullOrEmpty (this .orchestratorStartedVersion .getName ())) {
996+ versionName = this .orchestratorStartedVersion .getName ();
997+ }
998+
941999 // Create and invoke the workflow orchestrator
942- TaskOrchestrationFactory factory = TaskOrchestrationExecutor .this .orchestrationFactories
943- . get ( executionStarted . getName ());
1000+ TaskOrchestrationFactory factory = TaskOrchestrationExecutor .this .orchestrationFactories . getOrchestrationFactory ( executionStarted . getName (), versionName );
1001+
9441002 if (factory == null ) {
9451003 // Try getting the default orchestrator
946- factory = TaskOrchestrationExecutor .this .orchestrationFactories .get ("*" );
1004+ factory = TaskOrchestrationExecutor .this .orchestrationFactories .getOrchestrationFactory ("*" );
9471005 }
9481006 // TODO: Throw if the factory is null (orchestration by that name doesn't exist)
9491007 if (factory == null ) {
9501008 throw new IllegalStateException ("No factory found for orchestrator: " + executionStarted .getName ());
9511009 }
9521010
1011+ this .version = factory .getVersionName ();
1012+
9531013 TaskOrchestration orchestrator = factory .create ();
9541014 orchestrator .run (this );
9551015 break ;
@@ -959,6 +1019,9 @@ private void processEvent(OrchestratorService.HistoryEvent e) {
9591019 case EXECUTIONTERMINATED :
9601020 this .handleExecutionTerminated (e );
9611021 break ;
1022+ case EXECUTIONSTALLED :
1023+ this .logger .fine (() -> this .instanceId + ": Workflow execution stalled" );
1024+ break ;
9621025 case TASKSCHEDULED :
9631026 this .handleTaskScheduled (e );
9641027 break ;
@@ -998,6 +1061,22 @@ private void processEvent(OrchestratorService.HistoryEvent e) {
9981061 }
9991062 }
10001063
1064+ public void setVersionNotRegistered () {
1065+ this .pendingActions .clear ();
1066+
1067+ OrchestratorService .CompleteOrchestrationAction .Builder builder = OrchestratorService .CompleteOrchestrationAction
1068+ .newBuilder ();
1069+ builder .setOrchestrationStatus (OrchestratorService .OrchestrationStatus .ORCHESTRATION_STATUS_STALLED );
1070+
1071+ int id = this .sequenceNumber ++;
1072+ OrchestratorService .OrchestratorAction action = OrchestratorService .OrchestratorAction .newBuilder ()
1073+ .setId (id )
1074+ .setCompleteOrchestration (builder .build ())
1075+ .build ();
1076+ this .pendingActions .put (id , action );
1077+
1078+ }
1079+
10011080 private class TaskRecord <V > {
10021081 private final CompletableTask <V > task ;
10031082 private final String taskName ;
0 commit comments