Skip to content

Commit 4eaaec4

Browse files
authored
Update Java SDK reference docs (#213)
1 parent 0a5de73 commit 4eaaec4

1 file changed

Lines changed: 292 additions & 1 deletion

File tree

  • docs/sdk-reference/languages/java
Lines changed: 292 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,294 @@
11
# Java SDK
22

3-
Coming soon.
3+
The Java SDK (`aws-durable-execution-sdk-java`) runs in your Lambda functions and
4+
provides `DurableHandler`, `DurableContext`, durable operations, configurable
5+
serialization, and local/cloud testing utilities.
6+
7+
The SDK supports Java 17 and newer. Virtual threads require Java 21.
8+
9+
## Installation
10+
11+
Add the execution SDK to the Lambda function package. Replace the version with the
12+
latest release from
13+
[Maven Central](https://central.sonatype.com/artifact/software.amazon.lambda.durable/aws-durable-execution-sdk-java).
14+
15+
```xml
16+
<dependency>
17+
<groupId>software.amazon.lambda.durable</groupId>
18+
<artifactId>aws-durable-execution-sdk-java</artifactId>
19+
<version>1.2.1</version>
20+
</dependency>
21+
<dependency>
22+
<groupId>com.amazonaws</groupId>
23+
<artifactId>aws-lambda-java-core</artifactId>
24+
<version>1.4.0</version>
25+
</dependency>
26+
```
27+
28+
For local and cloud tests, add the testing SDK in test scope:
29+
30+
```xml
31+
<dependency>
32+
<groupId>software.amazon.lambda.durable</groupId>
33+
<artifactId>aws-durable-execution-sdk-java-testing</artifactId>
34+
<version>1.2.1</version>
35+
<scope>test</scope>
36+
</dependency>
37+
```
38+
39+
Package the Lambda as a shaded jar so the SDK and its dependencies are available at
40+
runtime:
41+
42+
```xml
43+
<plugin>
44+
<groupId>org.apache.maven.plugins</groupId>
45+
<artifactId>maven-shade-plugin</artifactId>
46+
<version>3.6.2</version>
47+
<configuration>
48+
<createDependencyReducedPom>false</createDependencyReducedPom>
49+
</configuration>
50+
<executions>
51+
<execution>
52+
<phase>package</phase>
53+
<goals><goal>shade</goal></goals>
54+
</execution>
55+
</executions>
56+
</plugin>
57+
```
58+
59+
## Usage
60+
61+
Extend `DurableHandler<I, O>` and implement `handleRequest(I input, DurableContext ctx)`.
62+
Use the context to create steps, waits, callbacks, child contexts, invokes, maps, and
63+
parallel branches.
64+
65+
```java
66+
import java.time.Duration;
67+
import software.amazon.lambda.durable.DurableContext;
68+
import software.amazon.lambda.durable.DurableHandler;
69+
70+
public class OrderProcessor extends DurableHandler<Order, OrderResult> {
71+
72+
@Override
73+
public OrderResult handleRequest(Order order, DurableContext ctx) {
74+
var reservation = ctx.step("reserve-inventory", Reservation.class,
75+
stepCtx -> inventoryService.reserve(order.items()));
76+
77+
ctx.wait("warehouse-delay", Duration.ofHours(2));
78+
79+
var shipment = ctx.step("ship-order", Shipment.class,
80+
stepCtx -> shippingService.ship(reservation, order.address()));
81+
82+
return new OrderResult(order.id(), shipment.trackingNumber());
83+
}
84+
}
85+
```
86+
87+
Operation names are required in Java. Use stable, descriptive names so replay can match
88+
new execution to checkpointed state.
89+
90+
## Configuration
91+
92+
Override `createConfiguration()` to customize serialization, the Lambda client, logging,
93+
polling, checkpoint batching, plugins, or the executor used for user-defined async work.
94+
95+
```java
96+
import java.time.Duration;
97+
import java.util.concurrent.Executors;
98+
import software.amazon.awssdk.regions.Region;
99+
import software.amazon.awssdk.services.lambda.LambdaClient;
100+
import software.amazon.lambda.durable.DurableConfig;
101+
import software.amazon.lambda.durable.DurableContext;
102+
import software.amazon.lambda.durable.DurableHandler;
103+
104+
public class ConfiguredHandler extends DurableHandler<Input, Output> {
105+
106+
@Override
107+
protected DurableConfig createConfiguration() {
108+
var lambdaClientBuilder = LambdaClient.builder()
109+
.region(Region.US_WEST_2);
110+
111+
return DurableConfig.builder()
112+
.withLambdaClientBuilder(lambdaClientBuilder)
113+
.withExecutorService(Executors.newFixedThreadPool(16))
114+
.withCheckpointDelay(Duration.ofMillis(10))
115+
.build();
116+
}
117+
118+
@Override
119+
public Output handleRequest(Input input, DurableContext ctx) {
120+
// Durable function logic
121+
}
122+
}
123+
```
124+
125+
The configured executor is used for user operations such as async steps and concurrent
126+
branches. Internal SDK polling and checkpoint coordination use SDK-managed threads.
127+
128+
## 2.x Upgrade
129+
130+
When upgrading from `1.x` to `2.x`, review the Java SDK migration guide in the
131+
[SDK repository](https://github.com/aws/aws-durable-execution-sdk-java/blob/main/docs/migration-1.x-to-2.x.md).
132+
The main changes are:
133+
134+
- Replace `StepConfig.builder().semantics(...)` with `semanticsPerRetry(...)`.
135+
- Preserve old `AT_MOST_ONCE_PER_RETRY` behavior by also setting
136+
`retryStrategy(RetryStrategies.Presets.NO_RETRY)`.
137+
- Update log queries and dashboards from `durableExecutionArn`, `contextId`, and
138+
`contextName` to `executionArn`, `operationId`, and `operationName`.
139+
- Move replay checks to `DurableContext.isReplaying()`; `StepContext` no longer exposes
140+
replay state.
141+
- Update tests and error handling that expect invalid context usage to throw
142+
`IllegalDurableOperationException`; `2.x` throws `IllegalStateException`.
143+
- Verify custom `SerDes` implementations can deserialize values immediately after
144+
serialization. `2.x` validates this round trip before checkpointing by default.
145+
146+
Useful searches before upgrading:
147+
148+
```console
149+
rg -n "\.semantics\(" .
150+
rg -n "durableExecutionArn|contextId|contextName" .
151+
rg -n "isReplaying|StepContext" .
152+
```
153+
154+
If you need a temporary log compatibility window, configure old MDC key names while
155+
dashboards are migrated:
156+
157+
```java
158+
import software.amazon.lambda.durable.DurableConfig;
159+
import software.amazon.lambda.durable.logging.LoggerConfig;
160+
161+
@Override
162+
protected DurableConfig createConfiguration() {
163+
return DurableConfig.builder()
164+
.withLoggerConfig(new LoggerConfig(true, true))
165+
.build();
166+
}
167+
```
168+
169+
## FAQ
170+
171+
### Can I use a virtual thread pool?
172+
173+
Yes. The SDK baseline is Java 17, so it does not use virtual threads by default. On
174+
Java 21 or newer, provide a virtual-thread executor through `DurableConfig`.
175+
176+
```java
177+
import java.util.concurrent.Executors;
178+
import software.amazon.lambda.durable.DurableConfig;
179+
180+
@Override
181+
protected DurableConfig createConfiguration() {
182+
return DurableConfig.builder()
183+
.withExecutorService(Executors.newVirtualThreadPerTaskExecutor())
184+
.build();
185+
}
186+
```
187+
188+
This executor only runs user-defined operation code. Virtual threads can help when you
189+
create many concurrent async steps or branches, but they do not remove Lambda memory,
190+
timeout, downstream service, or durable execution service limits.
191+
192+
### Can a Java durable function be triggered by SQS, SNS, EventBridge, or other event sources?
193+
194+
Yes, but Java event model deserialization needs care. The default user-data serializer is
195+
the SDK's Jackson-based `JacksonSerDes`, not the same serializer the Lambda Java runtime
196+
uses for event classes from `aws-lambda-java-events`. For broad event-source support, add
197+
the Lambda Java serialization library, which provides the
198+
`com.amazonaws.services.lambda.runtime.serialization` package, and route Lambda event
199+
classes through it.
200+
201+
```xml
202+
<dependency>
203+
<groupId>com.amazonaws</groupId>
204+
<artifactId>aws-lambda-java-serialization</artifactId>
205+
<version>VERSION</version>
206+
</dependency>
207+
```
208+
209+
Then provide a `SerDes` adapter:
210+
211+
```java
212+
import com.amazonaws.services.lambda.runtime.serialization.events.LambdaEventSerializers;
213+
import java.lang.reflect.Type;
214+
import software.amazon.lambda.durable.DurableConfig;
215+
import software.amazon.lambda.durable.TypeToken;
216+
import software.amazon.lambda.durable.serde.JacksonSerDes;
217+
import software.amazon.lambda.durable.serde.SerDes;
218+
219+
@Override
220+
protected DurableConfig createConfiguration() {
221+
return DurableConfig.builder()
222+
.withSerDes(new LambdaEventSerDes())
223+
.build();
224+
}
225+
226+
final class LambdaEventSerDes implements SerDes {
227+
private final SerDes fallback = new JacksonSerDes();
228+
private final ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
229+
230+
@Override
231+
public String serialize(Object value) {
232+
return fallback.serialize(value);
233+
}
234+
235+
@Override
236+
public <T> T deserialize(String data, TypeToken<T> typeToken) {
237+
Type type = typeToken.getType();
238+
if (type instanceof Class<?> clazz && isLambdaEvent(clazz)) {
239+
@SuppressWarnings("unchecked")
240+
var serializer = LambdaEventSerializers.serializerFor((Class<T>) clazz, classLoader);
241+
return serializer.fromJson(data);
242+
}
243+
244+
return fallback.deserialize(data, typeToken);
245+
}
246+
247+
private static boolean isLambdaEvent(Class<?> clazz) {
248+
return clazz.getName().startsWith("com.amazonaws.services.lambda.runtime.events.");
249+
}
250+
}
251+
```
252+
253+
This pattern addresses the event-trigger deserialization problem discussed in
254+
[aws/aws-durable-execution-sdk-java#366](https://github.com/aws/aws-durable-execution-sdk-java/issues/366).
255+
The configured `SerDes` is also used as the default for steps, child contexts, callbacks,
256+
and other operations unless an operation-specific config provides its own serializer.
257+
258+
### Can I use Lambda SnapStart?
259+
260+
Yes, but avoid the Java SDK default Lambda client if SnapStart restores a snapshot after
261+
the environment-variable credentials captured at initialization have expired. The
262+
default client uses `EnvironmentVariableCredentialsProvider`, which can cause
263+
authentication failures after restore.
264+
265+
For SnapStart, provide your own `LambdaClient` with a credentials provider that refreshes
266+
after restore, then pass it to `withLambdaClientBuilder(...)`:
267+
268+
```java
269+
import software.amazon.awssdk.auth.credentials.ContainerCredentialsProvider;
270+
import software.amazon.awssdk.regions.Region;
271+
import software.amazon.awssdk.services.lambda.LambdaClient;
272+
import software.amazon.lambda.durable.DurableConfig;
273+
274+
@Override
275+
protected DurableConfig createConfiguration() {
276+
var lambdaClientBuilder = LambdaClient.builder()
277+
.region(Region.of(System.getenv("AWS_REGION")))
278+
.credentialsProvider(ContainerCredentialsProvider.builder().build());
279+
280+
return DurableConfig.builder()
281+
.withLambdaClientBuilder(lambdaClientBuilder)
282+
.build();
283+
}
284+
```
285+
286+
If you customize the Lambda client for SnapStart, keep the region explicit and avoid
287+
caching resolved credentials yourself during initialization.
288+
289+
### Where is the Java SDK source and API reference?
290+
291+
The source is in
292+
[aws/aws-durable-execution-sdk-java](https://github.com/aws/aws-durable-execution-sdk-java).
293+
The generated Javadoc is published at
294+
[aws.github.io/aws-durable-execution-sdk-java/javadoc](https://aws.github.io/aws-durable-execution-sdk-java/javadoc/).

0 commit comments

Comments
 (0)