22// Licensed under the MIT License.
33package io .durabletask .samples ;
44
5- import com .azure .core .credential .AccessToken ;
5+ import com .azure .core .credential .TokenCredential ;
66import com .microsoft .durabletask .*;
77import com .microsoft .durabletask .client .azuremanaged .DurableTaskSchedulerClientExtensions ;
88import com .microsoft .durabletask .client .azuremanaged .DurableTaskSchedulerClientOptions ;
99import com .microsoft .durabletask .worker .azuremanaged .DurableTaskSchedulerWorkerExtensions ;
1010import com .microsoft .durabletask .worker .azuremanaged .DurableTaskSchedulerWorkerOptions ;
11- import com .microsoft .durabletask .shared .azuremanaged .AccessTokenCache ;
1211
13- import org .springframework .beans .factory .annotation .Qualifier ;
1412import org .springframework .boot .SpringApplication ;
1513import org .springframework .boot .autoconfigure .SpringBootApplication ;
1614import org .springframework .web .bind .annotation .*;
1715import org .springframework .context .ConfigurableApplicationContext ;
1816import org .springframework .context .annotation .Bean ;
19- import org .springframework .context .annotation .ComponentScan ;
2017import org .springframework .context .annotation .Configuration ;
21- import org .springframework .context .annotation .Import ;
2218import org .springframework .boot .context .properties .ConfigurationProperties ;
2319import org .springframework .boot .context .properties .EnableConfigurationProperties ;
24- import org .springframework .beans .factory .annotation .Value ;
2520import java .time .Duration ;
26- import io .grpc .Channel ;
27- import java .util .Objects ;
2821import com .azure .identity .DefaultAzureCredentialBuilder ;
29- import com .azure .core .credential .TokenCredential ;
30- import com .azure .core .credential .TokenRequestContext ;
3122
3223@ ConfigurationProperties (prefix = "durable.task" )
3324@ lombok .Data
3425class DurableTaskProperties {
3526 private String endpoint ;
36- private String hubName ;
27+ private String taskHubName ;
3728 private String resourceId = "https://durabletask.io" ;
38- private boolean allowInsecure = false ;
29+ private boolean allowInsecureCredentials = false ;
3930}
4031
4132/**
42- * Sample Spring Boot application demonstrating Azure Durable Task integration.
33+ * Sample Spring Boot application demonstrating Azure-managed Durable Task integration.
4334 * This sample shows how to:
44- * 1. Configure Durable Task with Spring Boot
35+ * 1. Configure Azure-managed Durable Task with Spring Boot
4536 * 2. Create orchestrations and activities
4637 * 3. Handle REST API endpoints for order processing
4738 */
@@ -65,150 +56,91 @@ public TokenCredential tokenCredential() {
6556 return new DefaultAzureCredentialBuilder ().build ();
6657 }
6758
68- @ Bean
69- public AccessTokenCache accessTokenCache (
70- TokenCredential credential ,
71- DurableTaskProperties properties ) {
72- if (credential == null ) {
73- return null ;
74- }
75- TokenRequestContext context = new TokenRequestContext ();
76- context .addScopes (new String [] { properties .getResourceId () + "/.default" });
77- return new AccessTokenCache (
78- credential , context , Duration .ofMinutes (5 )
79- );
80- }
81-
8259 @ Bean
8360 public DurableTaskGrpcWorker durableTaskWorker (
8461 DurableTaskProperties properties ,
8562 TokenCredential tokenCredential ) {
8663
87- // Create worker options
88- DurableTaskSchedulerWorkerOptions options = new DurableTaskSchedulerWorkerOptions ()
89- .setEndpoint (properties .getEndpoint ())
90- .setTaskHubName (properties .getHubName ())
91- .setResourceId (properties .getResourceId ())
92- .setAllowInsecure (properties .isAllowInsecure ())
93- .setTokenCredential (tokenCredential );
94-
95- // Create worker builder
96- DurableTaskGrpcWorkerBuilder builder = DurableTaskSchedulerWorkerExtensions .createWorkerBuilder (options );
97-
64+ // Create worker using Azure-managed extensions
65+ DurableTaskGrpcWorkerBuilder workerBuilder = DurableTaskSchedulerWorkerExtensions .createWorkerBuilder (
66+ properties .getEndpoint (),
67+ properties .getTaskHubName (),
68+ tokenCredential );
69+
9870 // Add orchestrations
99- builder .addOrchestration (new TaskOrchestrationFactory () {
100- @ Override
101- public String getName () {
102- return "ProcessOrderOrchestration" ;
71+ workerBuilder .addOrchestration ("ProcessOrderOrchestration" , ctx -> {
72+ // Get the order input as JSON string
73+ String orderJson = ctx .getInput (String .class );
74+
75+ // Process the order through multiple activities
76+ boolean isValid = ctx .callActivity ("ValidateOrder" , orderJson , Boolean .class ).await ();
77+ if (!isValid ) {
78+ ctx .complete ("{\" status\" : \" FAILED\" , \" message\" : \" Order validation failed\" }" );
79+ return ;
10380 }
10481
105- @ Override
106- public TaskOrchestration create () {
107- return ctx -> {
108- // Get the order input as JSON string
109- String orderJson = ctx .getInput (String .class );
110-
111- // Process the order through multiple activities
112- boolean isValid = ctx .callActivity ("ValidateOrder" , orderJson , Boolean .class ).await ();
113- if (!isValid ) {
114- ctx .complete ("{\" status\" : \" FAILED\" , \" message\" : \" Order validation failed\" }" );
115- return ;
116- }
117-
118- // Process payment
119- String paymentResult = ctx .callActivity ("ProcessPayment" , orderJson , String .class ).await ();
120- if (!paymentResult .contains ("\" success\" :true" )) {
121- ctx .complete ("{\" status\" : \" FAILED\" , \" message\" : \" Payment processing failed\" }" );
122- return ;
123- }
124-
125- // Ship order
126- String shipmentResult = ctx .callActivity ("ShipOrder" , orderJson , String .class ).await ();
127-
128- // Return the final result
129- ctx .complete ("{\" status\" : \" SUCCESS\" , " +
130- "\" payment\" : " + paymentResult + ", " +
131- "\" shipment\" : " + shipmentResult + "}" );
132- };
82+ // Process payment
83+ String paymentResult = ctx .callActivity ("ProcessPayment" , orderJson , String .class ).await ();
84+ if (!paymentResult .contains ("\" success\" :true" )) {
85+ ctx .complete ("{\" status\" : \" FAILED\" , \" message\" : \" Payment processing failed\" }" );
86+ return ;
13387 }
88+
89+ // Ship order
90+ String shipmentResult = ctx .callActivity ("ShipOrder" , orderJson , String .class ).await ();
91+
92+ // Return the final result
93+ ctx .complete ("{\" status\" : \" SUCCESS\" , " +
94+ "\" payment\" : " + paymentResult + ", " +
95+ "\" shipment\" : " + shipmentResult + "}" );
13496 });
13597
13698 // Add activity implementations
137- builder .addActivity (new TaskActivityFactory () {
138- @ Override
139- public String getName () { return "ValidateOrder" ; }
140-
141- @ Override
142- public TaskActivity create () {
143- return ctx -> {
144- String orderJson = ctx .getInput (String .class );
145- // Simple validation - check if order contains amount and it's greater than 0
146- return orderJson .contains ("\" amount\" " ) && !orderJson .contains ("\" amount\" :0" );
147- };
148- }
99+ workerBuilder .addActivity ("ValidateOrder" , ctx -> {
100+ String orderJson = ctx .getInput (String .class );
101+ // Simple validation - check if order contains amount and it's greater than 0
102+ return orderJson .contains ("\" amount\" " ) && !orderJson .contains ("\" amount\" :0" );
149103 });
150104
151- builder .addActivity (new TaskActivityFactory () {
152- @ Override
153- public String getName () { return "ProcessPayment" ; }
154-
155- @ Override
156- public TaskActivity create () {
157- return ctx -> {
158- String orderJson = ctx .getInput (String .class );
159- // Simulate payment processing
160- sleep (1000 ); // Simulate processing time
161- return "{\" success\" :true, \" transactionId\" :\" TXN" + System .currentTimeMillis () + "\" }" ;
162- };
163- }
105+ workerBuilder .addActivity ("ProcessPayment" , ctx -> {
106+ String orderJson = ctx .getInput (String .class );
107+ // Simulate payment processing
108+ sleep (1000 ); // Simulate processing time
109+ return "{\" success\" :true, \" transactionId\" :\" TXN" + System .currentTimeMillis () + "\" }" ;
164110 });
165111
166- builder .addActivity (new TaskActivityFactory () {
167- @ Override
168- public String getName () { return "ShipOrder" ; }
169-
170- @ Override
171- public TaskActivity create () {
172- return ctx -> {
173- String orderJson = ctx .getInput (String .class );
174- // Simulate shipping process
175- sleep (1000 ); // Simulate processing time
176- return "{\" trackingNumber\" :\" TRACK" + System .currentTimeMillis () + "\" }" ;
177- };
178- }
112+ workerBuilder .addActivity ("ShipOrder" , ctx -> {
113+ String orderJson = ctx .getInput (String .class );
114+ // Simulate shipping process
115+ sleep (1000 ); // Simulate processing time
116+ return "{\" trackingNumber\" :\" TRACK" + System .currentTimeMillis () + "\" }" ;
179117 });
180118
181- return builder .build ();
119+ return workerBuilder .build ();
182120 }
183121
184122 @ Bean
185123 public DurableTaskClient durableTaskClient (
186124 DurableTaskProperties properties ,
187125 TokenCredential tokenCredential ) {
188126
189- // Create client options
190- DurableTaskSchedulerClientOptions options = new DurableTaskSchedulerClientOptions ()
191- .setEndpoint (properties .getEndpoint ())
192- .setTaskHubName (properties .getHubName ())
193- .setResourceId (properties .getResourceId ())
194- .setAllowInsecure (properties .isAllowInsecure ())
195- .setTokenCredential (tokenCredential );
196-
197- // Create and return the client
198- return DurableTaskSchedulerClientExtensions .createClient (options );
127+ // Create client using Azure-managed extensions
128+ return DurableTaskSchedulerClientExtensions .createClient (
129+ properties .getEndpoint (),
130+ properties .getTaskHubName (),
131+ tokenCredential );
199132 }
200133 }
201134
202135 private static void sleep (int millis ) {
203136 try {
204137 Thread .sleep (millis );
205138 } catch (InterruptedException e ) {
206- // ignore
139+ Thread . currentThread (). interrupt ();
207140 }
208141 }
209142}
210143
211-
212144/**
213145 * REST Controller for handling order-related operations.
214146 */
@@ -249,11 +181,6 @@ public String getOrder(@PathVariable String instanceId) throws Exception {
249181 if (metadata == null ) {
250182 return "{\" error\" : \" Order not found\" }" ;
251183 }
252-
253- if (metadata .getRuntimeStatus () == OrchestrationRuntimeStatus .COMPLETED ) {
254- return metadata .readOutputAs (String .class );
255- } else {
256- return "{\" status\" : \" " + metadata .getRuntimeStatus () + "\" }" ;
257- }
184+ return metadata .readOutputAs (String .class );
258185 }
259186}
0 commit comments