Skip to content

Commit 738e7ed

Browse files
committed
Adapted README and DurableConfig
1 parent 51905ae commit 738e7ed

3 files changed

Lines changed: 112 additions & 104 deletions

File tree

README.md

Lines changed: 20 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,14 @@ Build resilient, long-running AWS Lambda functions that automatically checkpoint
1313
- **Replay Safety** – Functions deterministically resume from checkpoints after interruptions
1414
- **Type Safety** – Full generic type support for step results
1515

16+
## How It Works
17+
18+
Your durable function extends `DurableHandler<I, O>` and implements `handleRequest(I input, DurableContext ctx)`. The `DurableContext` is your interface to durable operations:
19+
20+
- `ctx.step()` – Execute code and checkpoint the result
21+
- `ctx.stepAsync()` – Start concurrent operations
22+
- `ctx.wait()` – Suspend execution without compute charges
23+
1624
## Quick Start
1725

1826
### Installation
@@ -183,7 +191,7 @@ protected DurableConfig createConfiguration() {
183191
.build();
184192

185193
return DurableConfig.builder()
186-
.withDurableExecutionClient(new LambdaDurableFunctionsClient(lambdaClient))
194+
.withLambdaClient(lambdaClient)
187195
.withSerDes(new MyCustomSerDes()) // Custom serialization
188196
.withExecutorService(Executors.newFixedThreadPool(10)) // Custom thread pool
189197
.build();
@@ -192,7 +200,7 @@ protected DurableConfig createConfiguration() {
192200

193201
| Option | Description | Default |
194202
|--------|-------------|---------|
195-
| `withDurableExecutionClient()` | Client for checkpoint operations | Auto-configured Lambda client |
203+
| `withLambdaClient()` | Custom AWS Lambda client | Auto-configured Lambda client |
196204
| `withSerDes()` | Serializer for step results | Jackson with default settings |
197205
| `withExecutorService()` | Thread pool for async step execution | Cached daemon thread pool |
198206

@@ -253,6 +261,15 @@ void testOrderProcessing() {
253261
}
254262
```
255263

264+
You can also pass a lambda directly instead of a handler instance:
265+
266+
```java
267+
var runner = LocalDurableTestRunner.create(Order.class, (order, ctx) -> {
268+
var result = ctx.step("process", String.class, () -> "done");
269+
return new OrderResult(order.getId(), result);
270+
});
271+
```
272+
256273
### Inspecting Operations
257274

258275
```java
@@ -304,38 +321,7 @@ assertEquals(ExecutionStatus.SUCCEEDED, result.getStatus());
304321

305322
## Deployment
306323

307-
The [examples](./examples) module includes a complete SAM template and deployment instructions.
308-
309-
```bash
310-
cd examples
311-
mvn clean package
312-
sam build
313-
sam deploy --guided
314-
```
315-
316-
Key deployment requirements:
317-
- `DurableConfig` in SAM template with `ExecutionTimeout` and `RetentionPeriodInDays`
318-
- IAM permissions for `lambda:CheckpointDurableExecutions` and `lambda:GetDurableExecutionState`
319-
320-
See [examples/template.yaml](./examples/template.yaml) and [examples/README.md](./examples/README.md) for details.
321-
322-
## Examples
323-
324-
| Example | Description |
325-
|---------|-------------|
326-
| [SimpleStepExample](./examples/src/main/java/com/amazonaws/lambda/durable/examples/SimpleStepExample.java) | Basic sequential steps |
327-
| [WaitExample](./examples/src/main/java/com/amazonaws/lambda/durable/examples/WaitExample.java) | Using wait operations |
328-
| [RetryExample](./examples/src/main/java/com/amazonaws/lambda/durable/examples/RetryExample.java) | Configuring retry strategies |
329-
| [GenericTypesExample](./examples/src/main/java/com/amazonaws/lambda/durable/examples/GenericTypesExample.java) | Working with generic types |
330-
| [CustomConfigExample](./examples/src/main/java/com/amazonaws/lambda/durable/examples/CustomConfigExample.java) | Custom Lambda client and SerDes |
331-
| [WaitAtLeastExample](./examples/src/main/java/com/amazonaws/lambda/durable/examples/WaitAtLeastExample.java) | Concurrent stepAsync() with wait() |
332-
| [RetryInProcessExample](./examples/src/main/java/com/amazonaws/lambda/durable/examples/RetryInProcessExample.java) | In-process retry with concurrent operations |
333-
| [WaitAtLeastInProcessExample](./examples/src/main/java/com/amazonaws/lambda/durable/examples/WaitAtLeastInProcessExample.java) | Wait completes before async step (no suspension) |
334-
335-
## Requirements
336-
337-
- Java 17+
338-
- AWS SDK for Java v2
324+
See [examples/README.md](./examples/README.md) for complete instructions on local testing, deployment, invoking functions, and running cloud integration tests.
339325

340326
## Documentation
341327

examples/README.md

Lines changed: 58 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,87 +1,94 @@
11
# AWS Lambda Durable Execution SDK Examples
22

3-
This module contains example applications demonstrating how to use the AWS Lambda Durable Execution SDK for Java.
3+
Example applications demonstrating the AWS Lambda Durable Execution SDK for Java.
44

5-
# Running Examples with JUnit Tests
5+
## Prerequisites
66

7-
The examples demonstrate both local and cloud testing approaches using the SDK's testing utilities:
7+
- Java 17+
8+
- Maven 3.8+
9+
- AWS SAM CLI (for deployment)
10+
- Docker (for SAM build)
11+
- AWS credentials configured
812

9-
## Local Testing (Fast, No AWS Required)
13+
## Local Testing
1014

11-
Use `LocalDurableTestRunner` for fast, in-memory testing without deploying to AWS Lambda:
15+
Run examples locally without AWS using `LocalDurableTestRunner`:
1216

1317
```bash
14-
# Run all example tests
18+
# First, build and install the SDK to local Maven repo (from project root)
19+
mvn clean install -DskipTests
20+
21+
cd examples
22+
23+
# Run all tests
1524
mvn test
1625

1726
# Run specific test
1827
mvn test -Dtest=SimpleStepExampleTest
1928
```
2029

21-
The local runner skips actual wait times and runs entirely in-memory, making tests fast and suitable for CI/CD pipelines.
30+
The local runner executes in-memory and skips wait durations—ideal for fast iteration and CI/CD.
2231

23-
## Cloud Testing (End-to-End)
32+
## Deploy to AWS
2433

25-
Use `CloudDurableTestRunner` for end-to-end testing against deployed Lambda functions:
34+
```bash
35+
cd examples
36+
mvn clean package
37+
sam build
38+
sam deploy --guided
39+
```
2640

27-
```java
28-
var runner = CloudDurableTestRunner.create(
29-
"arn:aws:lambda:us-east-1:123456789012:function:MyFunction",
30-
MyInput.class,
31-
MyOutput.class);
41+
On first deploy, SAM will prompt for stack name and region. Subsequent deploys use saved config:
3242

33-
var result = runner.run(new MyInput("test-data"));
43+
```bash
44+
sam deploy
3445
```
3546

36-
This approach tests the actual deployed function, including all AWS integrations and durable execution behavior.
47+
The SAM template configures:
48+
- `DurableConfig` with `ExecutionTimeout` and `RetentionPeriodInDays`
49+
- IAM permissions for `lambda:CheckpointDurableExecutions` and `lambda:GetDurableExecutionState`
3750

38-
# Running Examples with AWS SAM locally
51+
## Invoke Deployed Functions
3952

40-
**Build the project:**
41-
```bash
42-
mvn clean package
43-
```
53+
```bash
54+
sam remote invoke SimpleStepExampleFunction \
55+
--event '{"name":"World"}' \
56+
--stack-name durable-sdk-examples
57+
```
4458

45-
### Option 1: Local Lambda Endpoint
59+
## Cloud Integration Tests
4660

47-
Start a local Lambda endpoint:
61+
Run tests against deployed functions using `CloudDurableTestRunner`:
4862

4963
```bash
50-
sam local start-lambda
64+
cd examples
65+
mvn test -Dtest=CloudBasedIntegrationTest -Dtest.cloud.enabled=true
5166
```
5267

53-
In another terminal, invoke the function:
68+
The tests auto-detect your AWS account and region from credentials. Override if needed:
5469

5570
```bash
56-
# Invoke SimpleStepExample
57-
aws lambda invoke \
58-
--function-name SimpleStepExampleFunction \
59-
--endpoint-url http://127.0.0.1:3001 \
60-
--payload '{"name":"Alice"}' \
61-
--cli-binary-format raw-in-base64-out \
62-
response.json
63-
64-
# Invoke WaitExample
65-
aws lambda invoke \
66-
--function-name WaitExampleFunction \
67-
--endpoint-url http://127.0.0.1:3001 \
68-
--payload '{"name":"Bob"}' \
69-
--cli-binary-format raw-in-base64-out \
70-
response.json
71+
mvn test -Dtest=CloudBasedIntegrationTest \
72+
-Dtest.cloud.enabled=true \
73+
-Dtest.aws.account=123456789012 \
74+
-Dtest.aws.region=us-east-1
7175
```
7276

73-
### Option 2: Direct Invocation
77+
## Examples
7478

75-
Invoke the function directly:
79+
| Example | Description |
80+
|---------|-------------|
81+
| [SimpleStepExample](src/main/java/com/amazonaws/lambda/durable/examples/SimpleStepExample.java) | Basic sequential steps |
82+
| [WaitExample](src/main/java/com/amazonaws/lambda/durable/examples/WaitExample.java) | Suspend execution with `wait()` |
83+
| [RetryExample](src/main/java/com/amazonaws/lambda/durable/examples/RetryExample.java) | Configuring retry strategies |
84+
| [GenericTypesExample](src/main/java/com/amazonaws/lambda/durable/examples/GenericTypesExample.java) | Working with `List<T>` and `Map<K,V>` |
85+
| [CustomConfigExample](src/main/java/com/amazonaws/lambda/durable/examples/CustomConfigExample.java) | Custom Lambda client and SerDes |
86+
| [WaitAtLeastExample](src/main/java/com/amazonaws/lambda/durable/examples/WaitAtLeastExample.java) | Concurrent `stepAsync()` with `wait()` |
87+
| [RetryInProcessExample](src/main/java/com/amazonaws/lambda/durable/examples/RetryInProcessExample.java) | In-process retry with concurrent operations |
88+
| [WaitAtLeastInProcessExample](src/main/java/com/amazonaws/lambda/durable/examples/WaitAtLeastInProcessExample.java) | Wait completes before async step (no suspension) |
7689

77-
```bash
78-
sam local invoke SimpleStepExampleFunction \
79-
--event event.json
80-
```
90+
## Cleanup
8191

82-
Create `event.json`:
83-
```json
84-
{
85-
"name": "Alice"
86-
}
92+
```bash
93+
sam delete
8794
```

sdk/src/main/java/com/amazonaws/lambda/durable/DurableConfig.java

Lines changed: 34 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919

2020
/**
2121
* Configuration for DurableHandler initialization. This class provides a builder pattern for configuring SDK components
22-
* including DurableExecutionClient, SerDes, and ExecutorService.
22+
* including LambdaClient, SerDes, and ExecutorService.
2323
*
2424
* <p>Configuration is initialized once during Lambda cold start and remains immutable throughout the execution
2525
* lifecycle.
@@ -36,32 +36,18 @@
3636
* }
3737
* }</pre>
3838
*
39-
* <p>Example usage with custom Lambda client configuration using {@link LambdaDurableFunctionsClient}:
39+
* <p>Example usage with custom Lambda client:
4040
*
4141
* <pre>{@code
4242
* @Override
4343
* protected DurableConfig createConfiguration() {
44-
* // Create a custom Lambda client with specific configuration
4544
* LambdaClient lambdaClient = LambdaClient.builder()
4645
* .region(Region.US_WEST_2)
4746
* .credentialsProvider(ProfileCredentialsProvider.create("my-profile"))
48-
* .httpClient(ApacheHttpClient.builder()
49-
* .connectionTimeout(Duration.ofSeconds(30))
50-
* .socketTimeout(Duration.ofSeconds(60))
51-
* .build())
52-
* .overrideConfiguration(ClientOverrideConfiguration.builder()
53-
* .retryPolicy(RetryPolicy.builder()
54-
* .numRetries(5)
55-
* .build())
56-
* .build())
5747
* .build();
5848
*
59-
* // Wrap the Lambda client with LambdaDurableFunctionsClient
60-
* DurableExecutionClient durableClient = new LambdaDurableFunctionsClient(lambdaClient);
61-
*
62-
* // Configure DurableConfig with the custom client
6349
* return DurableConfig.builder()
64-
* .withDurableExecutionClient(durableClient)
50+
* .withLambdaClient(lambdaClient)
6551
* .build();
6652
* }
6753
* }</pre>
@@ -197,8 +183,37 @@ public static final class Builder {
197183
private Builder() {}
198184

199185
/**
200-
* Sets a custom DurableExecutionClient. This is useful for testing with mock clients or using custom backend
201-
* implementations.
186+
* Sets a custom LambdaClient for production use. Use this method to customize the AWS SDK client
187+
* with specific regions, credentials, timeouts, or retry policies.
188+
*
189+
* <p>Example:
190+
* <pre>{@code
191+
* LambdaClient lambdaClient = LambdaClient.builder()
192+
* .region(Region.US_WEST_2)
193+
* .credentialsProvider(ProfileCredentialsProvider.create("my-profile"))
194+
* .build();
195+
*
196+
* DurableConfig.builder()
197+
* .withLambdaClient(lambdaClient)
198+
* .build();
199+
* }</pre>
200+
*
201+
* @param lambdaClient Custom LambdaClient instance
202+
* @return This builder
203+
* @throws NullPointerException if lambdaClient is null
204+
*/
205+
public Builder withLambdaClient(LambdaClient lambdaClient) {
206+
Objects.requireNonNull(lambdaClient, "LambdaClient cannot be null");
207+
this.durableExecutionClient = new LambdaDurableFunctionsClient(lambdaClient);
208+
return this;
209+
}
210+
211+
/**
212+
* Sets a custom DurableExecutionClient.
213+
*
214+
* <p><b>Note:</b> This method is primarily intended for testing with mock clients
215+
* (e.g., {@code LocalMemoryExecutionClient}). For production use with a custom AWS SDK client,
216+
* prefer {@link #withLambdaClient(LambdaClient)}.
202217
*
203218
* @param durableExecutionClient Custom DurableExecutionClient instance
204219
* @return This builder

0 commit comments

Comments
 (0)