Skip to content

Commit cbfa05b

Browse files
torosentCopilot
andcommitted
Update sample to FanOutFanIn pattern with fresh screenshots
- Replaced chaining sample with Fan-Out/Fan-In pattern (5× GetWeather + CreateSummary) - Updated README.md to reflect FanOutFanIn span hierarchy - Captured updated Jaeger screenshots showing parallel activity spans Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 9174904 commit cbfa05b

File tree

5 files changed

+42
-57
lines changed

5 files changed

+42
-57
lines changed

samples/README.md

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -39,39 +39,37 @@ docker run -d --name jaeger \
3939

4040
## What the Sample Does
4141

42-
The `TracingPattern` sample:
42+
The `TracingPattern` sample demonstrates the **Fan-Out/Fan-In** pattern with distributed tracing:
4343

4444
1. Configures OpenTelemetry with an OTLP exporter pointing to Jaeger
4545
2. Connects a worker and client to the DTS emulator using a connection string
46-
3. Creates a parent span (`create_orchestration:TracingOrchestration`) and schedules an orchestration
47-
4. The orchestration chains three activities (`Reverse`, `Capitalize`, `AddSuffix`) and a sub-orchestration (`ChildOrchestration`)
46+
3. Creates a parent span (`create_orchestration:FanOutFanIn`) and schedules an orchestration
47+
4. The orchestration fans out 5 parallel `GetWeather` activities (Seattle, Tokyo, London, Paris, Sydney), fans in the results, then calls `CreateSummary` to aggregate
4848
5. The SDK automatically propagates trace context through the full execution chain
4949

5050
## Screenshots
5151

5252
### Jaeger — Trace Search Results
5353

54-
Shows the trace from `durabletask-java-tracing-sample` service with 10 spans covering the full orchestration lifecycle.
54+
Shows the trace from `durabletask-java-tracing-sample` service with spans covering the full fan-out/fan-in orchestration lifecycle.
5555

5656
![Jaeger trace search results](images/jaeger-trace-list-full.png)
5757

5858
### Jaeger — Trace Detail
5959

60-
Full span hierarchy showing parent-child relationships:
61-
- `create_orchestration:TracingOrchestration` (parent)
62-
- `orchestration:TracingOrchestration` (orchestration replays)
63-
- `activity:Reverse`
64-
- `activity:Capitalize`
65-
- `orchestration:ChildOrchestration` (sub-orchestration)
66-
- `activity:AddSuffix`
60+
Full span hierarchy showing the fan-out/fan-in pattern:
61+
- `create_orchestration:FanOutFanIn` (parent)
62+
- `orchestration:FanOutFanIn` (orchestration execution)
63+
- `activity:GetWeather` ×5 (parallel fan-out)
64+
- `activity:CreateSummary` (fan-in aggregation)
6765

6866
![Jaeger trace detail](images/jaeger-full-trace-detail.png)
6967

7068
### Jaeger — Span Attributes
7169

7270
Activity span showing attributes aligned with the .NET SDK schema:
7371
- `durabletask.type=activity`
74-
- `durabletask.task.name=Reverse`
72+
- `durabletask.task.name=GetWeather`
7573
- `durabletask.task.instance_id=<orchestrationId>`
7674
- `durabletask.task.task_id=0`
7775
- `otel.scope.name=Microsoft.DurableTask`
@@ -81,7 +79,7 @@ Activity span showing attributes aligned with the .NET SDK schema:
8179

8280
### DTS Dashboard — Completed Orchestrations
8381

84-
Both `TracingOrchestration` and `ChildOrchestration` completed successfully.
82+
The `FanOutFanIn` orchestration completed successfully with all activities.
8583

8684
![DTS Dashboard](images/dts-dashboard-completed.png)
8785

3.64 KB
Loading
5.37 KB
Loading
-677 Bytes
Loading

samples/src/main/java/io/durabletask/samples/TracingPattern.java

Lines changed: 31 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
import java.io.IOException;
2222
import java.time.Duration;
23+
import java.util.List;
2324
import java.util.concurrent.TimeoutException;
2425
import java.util.logging.Logger;
2526

@@ -89,62 +90,48 @@ public static void main(String[] args) throws IOException, InterruptedException,
8990
.createWorkerBuilder(connectionString)
9091
.addOrchestration(new TaskOrchestrationFactory() {
9192
@Override
92-
public String getName() { return "TracingOrchestration"; }
93+
public String getName() { return "FanOutFanIn"; }
9394

9495
@Override
9596
public TaskOrchestration create() {
9697
return ctx -> {
97-
String input = ctx.getInput(String.class);
98-
// Trace context is automatically propagated to activities via parentTraceContext
99-
String reversed = ctx.callActivity("Reverse", input, String.class).await();
100-
String upper = ctx.callActivity("Capitalize", reversed, String.class).await();
101-
// Sub-orchestration also receives the trace context
102-
String result = ctx.callSubOrchestrator(
103-
"ChildOrchestration", upper, String.class).await();
104-
ctx.complete(result);
105-
};
106-
}
107-
})
108-
.addOrchestration(new TaskOrchestrationFactory() {
109-
@Override
110-
public String getName() { return "ChildOrchestration"; }
111-
112-
@Override
113-
public TaskOrchestration create() {
114-
return ctx -> {
115-
String input = ctx.getInput(String.class);
116-
String result = ctx.callActivity("AddSuffix", input, String.class).await();
117-
ctx.complete(result);
98+
// Fan-out: schedule multiple parallel activities
99+
List<Task<String>> parallelTasks = new java.util.ArrayList<>();
100+
String[] cities = {"Seattle", "Tokyo", "London", "Paris", "Sydney"};
101+
for (String city : cities) {
102+
parallelTasks.add(
103+
ctx.callActivity("GetWeather", city, String.class));
104+
}
105+
106+
// Fan-in: wait for all activities to complete
107+
List<String> results = ctx.allOf(parallelTasks).await();
108+
109+
// Aggregate results
110+
String summary = ctx.callActivity(
111+
"CreateSummary", String.join(", ", results), String.class).await();
112+
113+
ctx.complete(summary);
118114
};
119115
}
120116
})
121117
.addActivity(new TaskActivityFactory() {
122-
@Override public String getName() { return "Reverse"; }
118+
@Override public String getName() { return "GetWeather"; }
123119
@Override public TaskActivity create() {
124120
return ctx -> {
125-
String input = ctx.getInput(String.class);
126-
logger.info("[Reverse] Processing: " + input);
127-
return new StringBuilder(input).reverse().toString();
128-
};
129-
}
130-
})
131-
.addActivity(new TaskActivityFactory() {
132-
@Override public String getName() { return "Capitalize"; }
133-
@Override public TaskActivity create() {
134-
return ctx -> {
135-
String input = ctx.getInput(String.class);
136-
logger.info("[Capitalize] Processing: " + input);
137-
return input.toUpperCase();
121+
String city = ctx.getInput(String.class);
122+
logger.info("[GetWeather] Getting weather for: " + city);
123+
try { Thread.sleep(20); } catch (InterruptedException e) { Thread.currentThread().interrupt(); }
124+
return city + "=72F";
138125
};
139126
}
140127
})
141128
.addActivity(new TaskActivityFactory() {
142-
@Override public String getName() { return "AddSuffix"; }
129+
@Override public String getName() { return "CreateSummary"; }
143130
@Override public TaskActivity create() {
144131
return ctx -> {
145132
String input = ctx.getInput(String.class);
146-
logger.info("[AddSuffix] Processing: " + input);
147-
return input + "-traced";
133+
logger.info("[CreateSummary] Creating summary for: " + input);
134+
return "Weather Report: " + input;
148135
};
149136
}
150137
})
@@ -160,19 +147,19 @@ public TaskOrchestration create() {
160147
.createClientBuilder(connectionString).build();
161148

162149
// Create a parent span — the SDK automatically propagates W3C trace context
163-
Span orchestrationSpan = tracer.spanBuilder("create_orchestration:TracingOrchestration")
164-
.setAttribute("durabletask.task.name", "TracingOrchestration")
150+
Span orchestrationSpan = tracer.spanBuilder("create_orchestration:FanOutFanIn")
151+
.setAttribute("durabletask.task.name", "FanOutFanIn")
165152
.setAttribute("durabletask.type", "orchestration")
166153
.startSpan();
167154

168155
orchestrationContext = Context.current().with(orchestrationSpan);
169156

170157
String instanceId;
171158
try (Scope scope = orchestrationSpan.makeCurrent()) {
172-
logger.info("Scheduling orchestration...");
159+
logger.info("Scheduling FanOutFanIn orchestration...");
173160
instanceId = client.scheduleNewOrchestrationInstance(
174-
"TracingOrchestration",
175-
new NewOrchestrationInstanceOptions().setInput("Hello, tracing!"));
161+
"FanOutFanIn",
162+
new NewOrchestrationInstanceOptions().setInput("weather-request"));
176163
orchestrationSpan.setAttribute("durabletask.task.instance_id", instanceId);
177164
logger.info("Started orchestration: " + instanceId);
178165
}

0 commit comments

Comments
 (0)