Skip to content

Commit 3f14ab9

Browse files
committed
update understanding the code sections for other languages
Signed-off-by: Hannah Hunter <[email protected]>
1 parent 7b1fdd8 commit 3f14ab9

File tree

1 file changed

+189
-60
lines changed

1 file changed

+189
-60
lines changed

articles/azure-functions/durable/durable-task-scheduler/quickstart-aca-azd-durable-task-sdk.md

Lines changed: 189 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -85,15 +85,15 @@ cd /samples/portable-sdks/dotnet/FunctionChaining
8585
::: zone pivot="python"
8686

8787
```bash
88-
cd /samples/portable-sdks/python/FunctionChaining
88+
cd /samples/portable-sdks/python/function-chaining
8989
```
9090

9191
::: zone-end
9292

9393
::: zone pivot="java"
9494

9595
```bash
96-
cd /samples/portable-sdks/java/FunctionChaining
96+
cd /samples/portable-sdks/java/function-chaining
9797
```
9898

9999
::: zone-end
@@ -201,20 +201,40 @@ In the Azure portal, verify the orchestrations are running successfully.
201201

202202
::: zone pivot="csharp"
203203

204-
### Client Project
204+
### Client project
205205

206206
The Client project:
207207

208208
- Uses the same connection string logic as the worker
209-
- Schedules an orchestration instance with a name input
210-
- Waits for the orchestration to complete and displays the result
211-
- Uses WaitForInstanceCompletionAsync for efficient polling
209+
- Implements a sequential orchestration scheduler that:
210+
- Schedules 20 orchestration instances, one at a time
211+
- Waits 5 seconds between scheduling each orchestration
212+
- Tracks all orchestration instances in a list
213+
- Waits for all orchestrations to complete before exiting
214+
- Uses standard logging to show progress and results
212215

213216
```csharp
214-
var instance = await client.WaitForInstanceCompletionAsync(
215-
instanceId,
216-
getInputsAndOutputs: true,
217-
cts.Token);
217+
// Schedule 20 orchestrations sequentially
218+
for (int i = 0; i < TotalOrchestrations; i++)
219+
{
220+
// Create a unique instance ID
221+
string instanceName = $"{name}_{i+1}";
222+
223+
// Schedule the orchestration
224+
string instanceId = await client.ScheduleNewOrchestrationInstanceAsync(
225+
"GreetingOrchestration",
226+
instanceName);
227+
228+
// Wait 5 seconds before scheduling the next one
229+
await Task.Delay(TimeSpan.FromSeconds(IntervalSeconds));
230+
}
231+
232+
// Wait for all orchestrations to complete
233+
foreach (string id in allInstanceIds)
234+
{
235+
OrchestrationMetadata instance = await client.WaitForInstanceCompletionAsync(
236+
id, getInputsAndOutputs: false, CancellationToken.None);
237+
}
218238
```
219239

220240
### Worker Project
@@ -254,7 +274,8 @@ public class SayHelloActivity : TaskActivity<string, string>
254274
}
255275
```
256276

257-
The worker uses Microsoft.Extensions.Hosting for proper lifecycle management:
277+
The worker uses `Microsoft.Extensions.Hosting` for proper lifecycle management:
278+
258279
```csharp
259280
var builder = Host.CreateApplicationBuilder();
260281
builder.Services.AddDurableTaskWorker()
@@ -270,89 +291,197 @@ await host.StartAsync();
270291

271292
::: zone pivot="python"
272293

273-
### Worker Project
274-
275-
The Worker project contains:
276-
277-
- ****: Defines the orchestrator and activity functions in a single file
278-
- ****: Sets up the worker host with proper connection string handling
294+
### Client
279295

280-
#### Orchestration Implementation
296+
The Client project:
281297

282-
The orchestration directly calls each activity in sequence using the standard `CallActivityAsync` method:
298+
- Uses the same connection string logic as the worker
299+
- Implements a sequential orchestration scheduler that:
300+
- Schedules 20 orchestration instances, one at a time
301+
- Waits 5 seconds between scheduling each orchestration
302+
- Tracks all orchestration instances in a list
303+
- Waits for all orchestrations to complete before exiting
304+
- Uses standard logging to show progress and results
283305

284306
```python
285-
307+
# Schedule a new orchestration instance
308+
instance_id = client.schedule_new_orchestration(
309+
"function_chaining_orchestrator",
310+
input=name
311+
)
312+
313+
logger.info(f"Started orchestration with ID = {instance_id}")
314+
315+
# Wait for orchestration to complete
316+
logger.info("Waiting for orchestration to complete...")
317+
result = client.wait_for_orchestration_completion(
318+
instance_id,
319+
timeout=30
320+
)
286321
```
287322

288-
Each activity is implemented as a separate class decorated with the `[DurableTask]` attribute:
289-
290-
```python
323+
### Worker
291324

292-
```
325+
#### Orchestration Implementation
293326

294-
The worker uses Microsoft.Extensions.Hosting for proper lifecycle management:
327+
The orchestration directly calls each activity in sequence using the standard `call_activity` function:
295328

296329
```python
297-
330+
# Orchestrator function
331+
def function_chaining_orchestrator(ctx, name: str) -> str:
332+
"""Orchestrator that demonstrates function chaining pattern."""
333+
logger.info(f"Starting function chaining orchestration for {name}")
334+
335+
# Call first activity - passing input directly without named parameter
336+
greeting = yield ctx.call_activity('say_hello', input=name)
337+
338+
# Call second activity with the result from first activity
339+
processed_greeting = yield ctx.call_activity('process_greeting', input=greeting)
340+
341+
# Call third activity with the result from second activity
342+
final_response = yield ctx.call_activity('finalize_response', input=processed_greeting)
343+
344+
return final_response
298345
```
299346

300-
### Client Project
347+
Each activity is implemented as a separate function:
301348

302-
The Client project:
349+
```python
350+
# Activity functions
351+
def say_hello(ctx, name: str) -> str:
352+
"""First activity that greets the user."""
353+
logger.info(f"Activity say_hello called with name: {name}")
354+
return f"Hello {name}!"
355+
356+
def process_greeting(ctx, greeting: str) -> str:
357+
"""Second activity that processes the greeting."""
358+
logger.info(f"Activity process_greeting called with greeting: {greeting}")
359+
return f"{greeting} How are you today?"
360+
361+
def finalize_response(ctx, response: str) -> str:
362+
"""Third activity that finalizes the response."""
363+
logger.info(f"Activity finalize_response called with response: {response}")
364+
return f"{response} I hope you're doing well!"
365+
```
303366

304-
- Uses the same connection string logic as the worker
305-
- Schedules an orchestration instance with a name input
306-
- Waits for the orchestration to complete and displays the result
307-
- Uses WaitForInstanceCompletionAsync for efficient polling
367+
The worker uses `DurableTaskSchedulerWorker` for proper lifecycle management:
308368

309369
```python
310-
370+
with DurableTaskSchedulerWorker(
371+
host_address=host_address,
372+
secure_channel=endpoint != "http://localhost:8080",
373+
taskhub=taskhub_name,
374+
token_credential=credential
375+
) as worker:
376+
377+
# Register activities and orchestrators
378+
worker.add_activity(say_hello)
379+
worker.add_activity(process_greeting)
380+
worker.add_activity(finalize_response)
381+
worker.add_orchestrator(function_chaining_orchestrator)
382+
383+
# Start the worker (without awaiting)
384+
worker.start()
311385
```
312386

313387

314388
::: zone-end
315389

316390
::: zone pivot="java"
317391

318-
### Worker Project
319-
320-
The Worker project contains:
321-
322-
- ****: Defines the orchestrator and activity functions in a single file
323-
- ****: Sets up the worker host with proper connection string handling
324-
325-
#### Orchestration Implementation
326-
327-
The orchestration directly calls each activity in sequence using the standard `CallActivityAsync` method:
328-
329-
```java
330-
331-
```
332-
333-
Each activity is implemented as a separate class decorated with the `[DurableTask]` attribute:
334-
335-
```java
392+
### Client
336393

337-
```
394+
The Client project:
338395

339-
The worker uses Microsoft.Extensions.Hosting for proper lifecycle management:
396+
- Uses the same connection string logic as the worker
397+
- Implements a sequential orchestration scheduler that:
398+
- Schedules 20 orchestration instances, one at a time
399+
- Waits 5 seconds between scheduling each orchestration
400+
- Tracks all orchestration instances in a list
401+
- Waits for all orchestrations to complete before exiting
402+
- Uses standard logging to show progress and results
340403

341404
```java
342-
405+
// Create client using Azure-managed extensions
406+
DurableTaskClient client = DurableTaskSchedulerClientExtensions.createClientBuilder(connectionString).build();
407+
408+
// Start a new instance of the registered "ActivityChaining" orchestration
409+
String instanceId = client.scheduleNewOrchestrationInstance(
410+
"ActivityChaining",
411+
new NewOrchestrationInstanceOptions().setInput("Hello, world!"));
412+
logger.info("Started new orchestration instance: {}", instanceId);
413+
414+
// Block until the orchestration completes. Then print the final status, which includes the output.
415+
OrchestrationMetadata completedInstance = client.waitForInstanceCompletion(
416+
instanceId,
417+
Duration.ofSeconds(30),
418+
true);
419+
logger.info("Orchestration completed: {}", completedInstance);
420+
logger.info("Output: {}", completedInstance.readOutputAs(String.class))
343421
```
344422

345-
### Client Project
423+
### Worker
346424

347-
The Client project:
425+
#### Orchestration Implementation
348426

349-
- Uses the same connection string logic as the worker
350-
- Schedules an orchestration instance with a name input
351-
- Waits for the orchestration to complete and displays the result
352-
- Uses WaitForInstanceCompletionAsync for efficient polling
427+
The orchestration directly calls each activity in sequence using the standard `callActivity` method:
353428

354429
```java
430+
DurableTaskGrpcWorker worker = DurableTaskSchedulerWorkerExtensions.createWorkerBuilder(connectionString)
431+
.addOrchestration(new TaskOrchestrationFactory() {
432+
@Override
433+
public String getName() { return "ActivityChaining"; }
434+
435+
@Override
436+
public TaskOrchestration create() {
437+
return ctx -> {
438+
String input = ctx.getInput(String.class);
439+
String x = ctx.callActivity("Reverse", input, String.class).await();
440+
String y = ctx.callActivity("Capitalize", x, String.class).await();
441+
String z = ctx.callActivity("ReplaceWhitespace", y, String.class).await();
442+
ctx.complete(z);
443+
};
444+
}
445+
})
446+
.addActivity(new TaskActivityFactory() {
447+
@Override
448+
public String getName() { return "Reverse"; }
449+
450+
@Override
451+
public TaskActivity create() {
452+
return ctx -> {
453+
String input = ctx.getInput(String.class);
454+
StringBuilder builder = new StringBuilder(input);
455+
builder.reverse();
456+
return builder.toString();
457+
};
458+
}
459+
})
460+
.addActivity(new TaskActivityFactory() {
461+
@Override
462+
public String getName() { return "Capitalize"; }
463+
464+
@Override
465+
public TaskActivity create() {
466+
return ctx -> ctx.getInput(String.class).toUpperCase();
467+
}
468+
})
469+
.addActivity(new TaskActivityFactory() {
470+
@Override
471+
public String getName() { return "ReplaceWhitespace"; }
472+
473+
@Override
474+
public TaskActivity create() {
475+
return ctx -> {
476+
String input = ctx.getInput(String.class);
477+
return input.trim().replaceAll("\\s", "-");
478+
};
479+
}
480+
})
481+
.build();
355482

483+
// Start the worker
484+
worker.start();
356485
```
357486

358487
::: zone-end

0 commit comments

Comments
 (0)