Customize SDK behavior by overriding createConfiguration() in your handler:
public class OrderProcessor extends DurableHandler<Order, OrderResult> {
@Override
protected DurableConfig createConfiguration() {
// Custom Lambda client with connection pooling
var lambdaClientBuilder = LambdaClient.builder()
.httpClient(ApacheHttpClient.builder()
.maxConnections(50)
.connectionTimeout(Duration.ofSeconds(30))
.build());
return DurableConfig.builder()
.withLambdaClientBuilder(lambdaClientBuilder)
.withSerDes(new MyCustomSerDes()) // Custom serialization
.withExecutorService(Executors.newFixedThreadPool(10)) // Custom thread pool
.withLoggerConfig(LoggerConfig.withReplayLogging()) // Enable replay logs
.build();
}
@Override
protected OrderResult handleRequest(Order order, DurableContext ctx) {
// Your handler logic
}
}| Option | Description | Default |
|---|---|---|
withLambdaClientBuilder() |
Custom AWS Lambda client | Auto-configured Lambda client |
withSerDes() |
Serializer for step results | Jackson with default settings |
withExecutorService() |
Thread pool for user-defined operations | Cached daemon thread pool |
withLoggerConfig() |
Logger behavior configuration | Suppress logs during replay |
withPollingStrategy() |
Backend polling strategy | Exponential backoff: 1s base, 2x rate, FULL jitter, 10s max |
withCheckpointDelay() |
How often the SDK checkpoints updates | Duration.ofSeconds(0) (as soon as possible) |
The withExecutorService() option configures the thread pool used for running user-defined operations. Internal SDK coordination (checkpoint batching, polling) runs on an SDK-managed thread pool.
Dynamic plugin loading is an opt-in alternative to registering plugins in application code. Put provider JARs on the application class path, then set DURABLE_EXECUTION_PLUGINS to an ordered, comma-separated list of provider names:
DURABLE_EXECUTION_PLUGINS=otel-invocation,com.example.audit
When the variable is unset or blank, the SDK does not perform provider discovery. During DurableConfig construction, the SDK uses ServiceLoader and the thread context class loader to find DurableExecutionPluginProvider implementations. Only named providers create plugins.
Dynamically loaded plugins run first in the order listed in DURABLE_EXECUTION_PLUGINS. Plugins registered through withPlugins(...) follow in configuration order. Both sources are additive: if the same plugin type is selected dynamically and registered explicitly, both instances are registered and receive lifecycle hooks. Duplicate configured provider names, duplicate discovered provider names, missing providers, incompatible provider API versions, invalid plugin types, and provider construction failures stop configuration with an IllegalStateException.
To distribute a provider in a Lambda layer, package its JAR under java/lib:
my-plugin-layer.zip
`-- java
`-- lib
`-- my-durable-plugin.jar
The provider JAR must contain:
META-INF/services/software.amazon.lambda.durable.plugin.DurableExecutionPluginProvider
The service file contains the provider implementation class name. A minimal provider looks like:
public final class AuditPluginProvider implements DurableExecutionPluginProvider {
@Override
public String getName() {
return "com.example.audit";
}
@Override
public int getApiVersion() {
return API_VERSION;
}
@Override
public Class<? extends DurableExecutionPlugin> getPluginType() {
return AuditPlugin.class;
}
@Override
public DurableExecutionPlugin createPlugin() {
return new AuditPlugin();
}
}Provider-specific settings can use namespaced environment variables. If an application shades provider JARs into one artifact, its build must preserve and merge META-INF/services entries.