Skip to content

Commit dc579ec

Browse files
committed
Add demo combining StructuredTaskScope and ScopeValue
1 parent ffb2589 commit dc579ec

File tree

3 files changed

+117
-0
lines changed

3 files changed

+117
-0
lines changed

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ java -cp target/classes --enable-preview eu.happycoders.structuredconcurrency/de
3232
java -cp target/classes --enable-preview eu.happycoders.structuredconcurrency/demo2_address/AddressVerification2_ShutdownOnSuccess
3333
java -cp target/classes --enable-preview eu.happycoders.structuredconcurrency/demo3_suppliers/SupplierDeliveryTimeCheck2_StructuredTaskScope
3434
java -cp target/classes --enable-preview eu.happycoders.structuredconcurrency/demo3_suppliers/SupplierDeliveryTimeCheck3_NestedStructuredTaskScope
35+
java -cp target/classes --enable-preview eu.happycoders.structuredconcurrency/demo3_suppliers/SupplierDeliveryTimeCheck4_NestedStructuredTaskScopeUsingScopedValue
3536
```
3637

3738
## Java Downloads
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
package eu.happycoders.structuredconcurrency.demo3_suppliers;
2+
3+
import static eu.happycoders.structuredconcurrency.util.SimpleLogger.log;
4+
5+
import eu.happycoders.structuredconcurrency.demo3_suppliers.model.SupplierDeliveryTime;
6+
import eu.happycoders.structuredconcurrency.demo3_suppliers.service.SupplierDeliveryTimeServiceUsingScopedValue;
7+
import java.util.List;
8+
import java.util.concurrent.StructuredTaskScope;
9+
import java.util.concurrent.StructuredTaskScope.Subtask;
10+
import java.util.concurrent.StructuredTaskScope.Subtask.State;
11+
12+
public class SupplierDeliveryTimeCheck4_NestedStructuredTaskScopeUsingScopedValue {
13+
14+
private static final boolean FAIL_ALL = false;
15+
16+
public static void main(String[] args) throws Exception {
17+
SupplierDeliveryTimeCheck4_NestedStructuredTaskScopeUsingScopedValue supplierDeliveryTimeCheck =
18+
new SupplierDeliveryTimeCheck4_NestedStructuredTaskScopeUsingScopedValue(
19+
new SupplierDeliveryTimeServiceUsingScopedValue(FAIL_ALL));
20+
List<SupplierDeliveryTime> responses =
21+
supplierDeliveryTimeCheck.getSupplierDeliveryTimes(
22+
List.of("B004V9OA84", "0201310090", "0134685997"),
23+
List.of("A", "B", "C", "D", "E"),
24+
"t0p-s3cr3t");
25+
log("Responses: " + responses);
26+
}
27+
28+
private final SupplierDeliveryTimeServiceUsingScopedValue service;
29+
30+
public SupplierDeliveryTimeCheck4_NestedStructuredTaskScopeUsingScopedValue(
31+
SupplierDeliveryTimeServiceUsingScopedValue service) {
32+
this.service = service;
33+
}
34+
35+
public static final ScopedValue<String> API_KEY = ScopedValue.newInstance();
36+
37+
List<SupplierDeliveryTime> getSupplierDeliveryTimes(
38+
List<String> productIds, List<String> supplierIds, String apiKey) throws Exception {
39+
return ScopedValue.where(API_KEY, apiKey)
40+
.call(() -> getSupplierDeliveryTimes(productIds, supplierIds));
41+
}
42+
43+
List<SupplierDeliveryTime> getSupplierDeliveryTimes(
44+
List<String> productIds, List<String> supplierIds) throws InterruptedException {
45+
try (StructuredTaskScope<SupplierDeliveryTime> scope = new StructuredTaskScope<>()) {
46+
List<Subtask<SupplierDeliveryTime>> subtasks =
47+
productIds.stream()
48+
.map(productId -> scope.fork(() -> getSupplierDeliveryTime(productId, supplierIds)))
49+
.toList();
50+
51+
scope.join();
52+
53+
return subtasks.stream()
54+
.filter(subtask -> subtask.state() == State.SUCCESS)
55+
.map(Subtask::get)
56+
.toList();
57+
}
58+
}
59+
60+
SupplierDeliveryTime getSupplierDeliveryTime(String productId, List<String> supplierIds)
61+
throws SupplierDeliveryTimeCheckException, InterruptedException {
62+
try (GetFastestDeliveryTimeScope scope = new GetFastestDeliveryTimeScope()) {
63+
for (String supplierId : supplierIds) {
64+
scope.fork(() -> service.getDeliveryTime(productId, supplierId));
65+
}
66+
67+
scope.join();
68+
return scope.result();
69+
}
70+
}
71+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package eu.happycoders.structuredconcurrency.demo3_suppliers.service;
2+
3+
import static eu.happycoders.structuredconcurrency.demo3_suppliers.SupplierDeliveryTimeCheck4_NestedStructuredTaskScopeUsingScopedValue.API_KEY;
4+
import static eu.happycoders.structuredconcurrency.util.SimpleLogger.log;
5+
6+
import eu.happycoders.structuredconcurrency.demo3_suppliers.model.SupplierDeliveryTime;
7+
import java.util.concurrent.ThreadLocalRandom;
8+
9+
public class SupplierDeliveryTimeServiceUsingScopedValue {
10+
11+
private final boolean failAll;
12+
13+
public SupplierDeliveryTimeServiceUsingScopedValue(boolean failAll) {
14+
this.failAll = failAll;
15+
}
16+
17+
public SupplierDeliveryTime getDeliveryTime(String productId, String supplier)
18+
throws InterruptedException {
19+
String apiKey = API_KEY.get();
20+
log(
21+
"Retrieving delivery time from supplier %s (using API key %s)..."
22+
.formatted(supplier, apiKey));
23+
24+
try {
25+
Thread.sleep(ThreadLocalRandom.current().nextLong(250, 1000));
26+
} catch (InterruptedException e) {
27+
log("Retrieving delivery time from supplier " + supplier + " interrupted");
28+
throw e;
29+
}
30+
31+
// 40% failure probability --> 2 out of 5 requests should fail
32+
if (failAll || ThreadLocalRandom.current().nextDouble() < 0.4) {
33+
log("Error retrieving delivery time from supplier " + supplier);
34+
throw new RuntimeException("Error retrieving delivery time from supplier " + supplier);
35+
}
36+
37+
int deliveryTimeHours = ThreadLocalRandom.current().nextInt(1, 7 * 24);
38+
39+
log(
40+
"Finished retrieving delivery time from supplier %s: %d hours"
41+
.formatted(supplier, deliveryTimeHours));
42+
43+
return new SupplierDeliveryTime(supplier, deliveryTimeHours);
44+
}
45+
}

0 commit comments

Comments
 (0)