diff --git a/examples/src/main/java/software/amazon/lambda/durable/examples/general/CustomConfigExample.java b/examples/src/main/java/software/amazon/lambda/durable/examples/general/CustomConfigExample.java index 28d248395..5bbd902b0 100644 --- a/examples/src/main/java/software/amazon/lambda/durable/examples/general/CustomConfigExample.java +++ b/examples/src/main/java/software/amazon/lambda/durable/examples/general/CustomConfigExample.java @@ -31,6 +31,7 @@ *
When enabled, the SDK validates serialized operation results and exceptions before checkpointing them. This
+ * catches incompatible SerDes behavior early at the cost of an extra deserialize pass. Defaults to true, and custom
+ * SerDes implementations are still expected to be round-trip safe even if this validation is disabled.
+ *
+ * @return true when round-trip serialization validation is enabled
+ */
+ public boolean shouldValidateSerializationRoundTrip() {
+ return validateSerializationRoundTrip;
+ }
+
/**
* Gets the plugin runner that dispatches lifecycle events to registered plugins.
*
@@ -293,6 +308,7 @@ public static final class Builder {
private LoggerConfig loggerConfig;
private PollingStrategy pollingStrategy;
private Duration checkpointDelay;
+ private boolean validateSerializationRoundTrip = true;
private List This validation is enabled by default. Disable it only to avoid the extra deserialize pass when the
+ * additional safety check is too expensive for your workload. Custom SerDes implementations are still expected
+ * to round-trip SDK-managed values correctly.
+ *
+ * @param validateSerializationRoundTrip true to validate serialized data with an immediate deserialize pass
+ * @return This builder
+ */
+ public Builder withSerializationRoundTripValidation(boolean validateSerializationRoundTrip) {
+ this.validateSerializationRoundTrip = validateSerializationRoundTrip;
+ return this;
+ }
+
/**
* Registers one or more plugins for lifecycle event instrumentation.
*
diff --git a/sdk/src/main/java/software/amazon/lambda/durable/DurableHandler.java b/sdk/src/main/java/software/amazon/lambda/durable/DurableHandler.java
index a31c94d00..6fceee077 100644
--- a/sdk/src/main/java/software/amazon/lambda/durable/DurableHandler.java
+++ b/sdk/src/main/java/software/amazon/lambda/durable/DurableHandler.java
@@ -117,6 +117,7 @@ public DurableConfig getConfiguration() {
* .withDurableExecutionClient(durableClient)
* .withSerDes(customSerDes) // Optional: custom SerDes for user data
* .withExecutorService(customExecutor) // Optional: custom thread pool
+ * .withSerializationRoundTripValidation(false) // Optional: skip extra validation deserialize pass
* .build();
* }
* }
diff --git a/sdk/src/main/java/software/amazon/lambda/durable/operation/ChildContextOperation.java b/sdk/src/main/java/software/amazon/lambda/durable/operation/ChildContextOperation.java
index acdda283b..f2fa1a561 100644
--- a/sdk/src/main/java/software/amazon/lambda/durable/operation/ChildContextOperation.java
+++ b/sdk/src/main/java/software/amazon/lambda/durable/operation/ChildContextOperation.java
@@ -149,6 +149,8 @@ private void executeChildContext() {
}
private void handleChildContextSuccess(T result) {
+ var serializedResult = serializeResultWithDeserializedValue(result);
+
if (replayChildren.get() || isVirtual || parentOperation != null && parentOperation.isOperationCompleted()) {
// Skip checkpointing if
// - parent ConcurrencyOperation has already completed, preventing race conditions where a child finishes
@@ -156,23 +158,22 @@ private void handleChildContextSuccess(T result) {
// - replaying a SUCCEEDED child with replayChildren=true — skip checkpointing.
// - nestingType is FLAT
// Mark the completableFuture completed so get() doesn't block waiting for a checkpoint response.
- cachedOperationResult.set(DeserializedOperationResult.succeeded(result));
+ cachedOperationResult.set(DeserializedOperationResult.succeeded(serializedResult.deserialized()));
markAlreadyCompleted();
} else {
- checkpointSuccess(result);
+ checkpointSuccess(serializedResult);
}
}
- private void checkpointSuccess(T result) {
- var serialized = serializeResult(result);
-
+ private void checkpointSuccess(SerializedResult