Skip to content

Commit ea5c08e

Browse files
authored
[feature] add an optional stepContext parameter (#130)
* add an optional stepContext parameter * rename parent context id to context id * rename parameter * update loggin example * add some comments * update DurableLogger to use StepContext class * update docs and examples to use child context logger * add more javadoc and minor code cleanups * add more comments and remove registration from context * fix of test cases
1 parent 21b130d commit ea5c08e

22 files changed

Lines changed: 384 additions & 362 deletions

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -354,8 +354,8 @@ The SDK provides a `DurableLogger` via `ctx.getLogger()` that automatically incl
354354
protected OrderResult handleRequest(Order order, DurableContext ctx) {
355355
ctx.getLogger().info("Processing order: {}", order.getId());
356356

357-
var result = ctx.step("validate", String.class, () -> {
358-
ctx.getLogger().debug("Validating order details");
357+
var result = ctx.step("validate", String.class, stepCtx -> {
358+
stepCtx.getLogger().debug("Validating order details");
359359
return validate(order);
360360
});
361361

examples/src/main/java/software/amazon/lambda/durable/examples/CallbackExample.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,13 +47,13 @@ public String handleRequest(ApprovalRequest input, DurableContext context) {
4747
var callback = context.createCallback("approval", String.class, config);
4848

4949
// Step 2.5: Log AWS CLI command to complete the callback
50-
context.step("log-callback-command", Void.class, () -> {
50+
context.step("log-callback-command", Void.class, ctx -> {
5151
var callbackId = callback.callbackId();
5252
// The result must be base64-encoded JSON
5353
var command = String.format(
5454
"aws lambda send-durable-execution-callback-success --callback-id %s --result $(echo -n '\"approved\"' | base64)",
5555
callbackId);
56-
context.getLogger().info("To complete this callback, run: {}", command);
56+
ctx.getLogger().info("To complete this callback, run: {}", command);
5757
return null;
5858
});
5959

examples/src/main/java/software/amazon/lambda/durable/examples/ChildContextExample.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ public String handleRequest(GreetingRequest input, DurableContext context) {
3131
// Child context 1: Order validation — step + wait + step
3232
var orderFuture = context.runInChildContextAsync("order-validation", String.class, child -> {
3333
var prepared = child.step("prepare-order", String.class, () -> "Order for " + name);
34-
context.getLogger().info("Order prepared, waiting for validation");
34+
child.getLogger().info("Order prepared, waiting for validation");
3535

3636
child.wait("validation-delay", Duration.ofSeconds(5));
3737

@@ -41,7 +41,7 @@ public String handleRequest(GreetingRequest input, DurableContext context) {
4141
// Child context 2: Inventory check — step + wait + step
4242
var inventoryFuture = context.runInChildContextAsync("inventory-check", String.class, child -> {
4343
var stock = child.step("check-stock", String.class, () -> "Stock available for " + name);
44-
context.getLogger().info("Stock checked, waiting for confirmation");
44+
child.getLogger().info("Stock checked, waiting for confirmation");
4545

4646
child.wait("confirmation-delay", Duration.ofSeconds(3));
4747

examples/src/main/java/software/amazon/lambda/durable/examples/LoggingExample.java

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,24 +15,22 @@ public class LoggingExample extends DurableHandler<GreetingRequest, String> {
1515

1616
@Override
1717
public String handleRequest(GreetingRequest input, DurableContext context) {
18-
var logger = context.getLogger();
19-
2018
// Log at execution level (outside any step)
21-
logger.info("Processing greeting for: {}", input.getName());
19+
context.getLogger().info("Processing greeting for: {}", input.getName());
2220

2321
// Step 1: Create greeting - logs inside step include operation context
24-
var greeting = context.step("create-greeting", String.class, () -> {
25-
logger.info("Creating greeting message");
22+
var greeting = context.step("create-greeting", String.class, ctx -> {
23+
ctx.getLogger().info("Creating greeting message");
2624
return "Hello, " + input.getName();
2725
});
2826

2927
// Step 2: Transform
30-
var result = context.step("transform", String.class, () -> {
31-
logger.info("Transforming greeting to uppercase");
28+
var result = context.step("transform", String.class, ctx -> {
29+
ctx.getLogger().info("Transforming greeting to uppercase");
3230
return greeting.toUpperCase() + "!";
3331
});
3432

35-
logger.info("Completed processing, result: {}", result);
33+
context.getLogger().info("Completed processing, result: {}", result);
3634
return result;
3735
}
3836
}

examples/src/main/java/software/amazon/lambda/durable/examples/RetryExample.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ public class RetryExample extends DurableHandler<Object, String> {
3131
@Override
3232
public String handleRequest(Object input, DurableContext context) {
3333
// Step 1: Record start time
34-
startTime = context.step("record-start-time", Instant.class, Instant::now);
34+
startTime = context.step("record-start-time", Instant.class, () -> Instant.now());
3535
logger.info("Recorded start time: {}", startTime);
3636

3737
// Step 2: Call that never retries (fails immediately)
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
package software.amazon.lambda.durable;
4+
5+
import com.amazonaws.services.lambda.runtime.Context;
6+
import software.amazon.lambda.durable.execution.ExecutionManager;
7+
import software.amazon.lambda.durable.logging.DurableLogger;
8+
9+
public abstract class BaseContext {
10+
protected final ExecutionManager executionManager;
11+
private final DurableConfig durableConfig;
12+
private final Context lambdaContext;
13+
private final ExecutionContext executionContext;
14+
private final String contextId;
15+
private boolean isReplaying;
16+
17+
/** Creates a new BaseContext instance. */
18+
protected BaseContext(
19+
ExecutionManager executionManager, DurableConfig durableConfig, Context lambdaContext, String contextId) {
20+
this.executionManager = executionManager;
21+
this.durableConfig = durableConfig;
22+
this.lambdaContext = lambdaContext;
23+
this.contextId = contextId;
24+
this.executionContext = new ExecutionContext(executionManager.getDurableExecutionArn());
25+
this.isReplaying = executionManager.hasOperationsForContext(contextId);
26+
}
27+
28+
// =============== accessors ================
29+
/**
30+
* Gets a logger with additional information of the current execution context.
31+
*
32+
* @return a DurableLogger instance
33+
*/
34+
public abstract DurableLogger getLogger();
35+
36+
/**
37+
* Returns the AWS Lambda runtime context.
38+
*
39+
* @return the Lambda context
40+
*/
41+
public Context getLambdaContext() {
42+
return lambdaContext;
43+
}
44+
45+
/**
46+
* Returns metadata about the current durable execution.
47+
*
48+
* <p>The execution context provides information that remains constant throughout the execution lifecycle, such as
49+
* the durable execution ARN. This is useful for tracking execution progress, correlating logs, and referencing this
50+
* execution in external systems.
51+
*
52+
* @return the execution context
53+
*/
54+
public ExecutionContext getExecutionContext() {
55+
return executionContext;
56+
}
57+
58+
/**
59+
* Returns the configuration for durable execution behavior.
60+
*
61+
* @return the durable configuration
62+
*/
63+
public DurableConfig getDurableConfig() {
64+
return durableConfig;
65+
}
66+
67+
// ============= internal utilities ===============
68+
69+
/** Gets the context ID for this context. Null for root context, set for child contexts. */
70+
public String getContextId() {
71+
return contextId;
72+
}
73+
74+
public ExecutionManager getExecutionManager() {
75+
return executionManager;
76+
}
77+
78+
/** Returns whether this context is currently in replay mode. */
79+
boolean isReplaying() {
80+
return isReplaying;
81+
}
82+
83+
/**
84+
* Transitions this context from replay to execution mode. Called when the first un-cached operation is encountered.
85+
*/
86+
void setExecutionMode() {
87+
this.isReplaying = false;
88+
}
89+
}

0 commit comments

Comments
 (0)