Summary
As part of our ongoing effort to make Powertools fully AOT compatible, we're thrilled to announce Idempotency support for native ahead-of-time (AOT) compilation.
Additionally, we've introduced custom key prefix support for Idempotency.
We've also addressed a bug in our Tracing utility that affected implementations using Top Level Statements.
Special thanks to @nCubed for bringing the Tracing issue to our attention.
Idempotency AOT
To enable Idempotency utility with AOT support, you need to configure the serialization context by adding WithJsonSerializationContext() to your Idempotency configuration.
In the example below, we use the default LambdaFunctionJsonSerializerContext. If you're using the Logging utility, you can alternatively use the PowertoolsSourceGeneratorSerializer.For more information visit our documentation
Idempotency.Configure(builder =>
builder.WithJsonSerializationContext(LambdaFunctionJsonSerializerContext.Default)));
Full example
public static class Function
{
private static async Task Main()
{
var tableName = Environment.GetEnvironmentVariable("IDEMPOTENCY_TABLE_NAME");
Idempotency.Configure(builder =>
builder
.WithJsonSerializationContext(LambdaFunctionJsonSerializerContext.Default)
.WithOptions(optionsBuilder => optionsBuilder
.WithExpiration(TimeSpan.FromHours(1)))
.UseDynamoDb(storeBuilder => storeBuilder
.WithTableName(tableName)
));
Func<APIGatewayProxyRequest, ILambdaContext, APIGatewayProxyResponse> handler = FunctionHandler;
await LambdaBootstrapBuilder.Create(handler,
new SourceGeneratorLambdaJsonSerializer<LambdaFunctionJsonSerializerContext>())
.Build()
.RunAsync();
}
[Idempotent]
public static APIGatewayProxyResponse FunctionHandler(APIGatewayProxyRequest apigwProxyEvent,
ILambdaContext context)
{
return new APIGatewayProxyResponse
{
Body = JsonSerializer.Serialize(response, typeof(Response), LambdaFunctionJsonSerializerContext.Default),
StatusCode = 200,
Headers = new Dictionary<string, string> { { "Content-Type", "application/json" } }
};
}
}
[JsonSerializable(typeof(APIGatewayProxyRequest))]
[JsonSerializable(typeof(APIGatewayProxyResponse))]
[JsonSerializable(typeof(Response))]
public partial class LambdaFunctionJsonSerializerContext : JsonSerializerContext
{
}
Idempotency custom key prefix
By default, the idempotency key follows the format [ClassName].[DecoratedMethodName]#[PayloadHash].
With this release, You can now customize this prefix by setting the KeyPrefix property in the Idempotency decorator, making code refactoring more manageable without impacting existing idempotency items.
public class Function
{
public Function()
{
var tableName = Environment.GetEnvironmentVariable("IDEMPOTENCY_TABLE_NAME");
Idempotency.Configure(builder => builder.UseDynamoDb(tableName));
}
[Idempotent(KeyPrefix = "MyCustomKeyPrefix")]
public APIGatewayProxyResponse FunctionHandler(APIGatewayProxyRequest apigwProxyEvent, ILambdaContext context)
{
return TestHelper.TestMethod(apigwProxyEvent);
}
}
Tracing segment name sanitization
Tracing segment name docs and X-Ray docs
Previously, string names automatically generated from Tracing-decorated methods weren't sanitized, which could silently fail and prevent traces from appearing in X-Ray due to invalid characters. While this could be addressed by specifying a custom segment name in the Tracing decorator, the custom string itself might still contain invalid characters.
To resolve this, we've implemented two improvements:
- Added documentation describing valid characters for segment names
- Implemented automatic string sanitization for both auto-generated and custom segment names
These changes ensure that no traces are dropped due to invalid characters in segment names, maintaining reliable trace data collection in X-Ray.
/// <summary>
/// Set custom segment name for the operation.
/// The default is '## {MethodName}'.
///
/// The logical name of the service that handled the request, up to 200 characters.
/// Names can contain Unicode letters, numbers, and whitespace, and the following symbols: \_, ., :, /, %, &, #, =, +, \\, -, @
/// </summary>
public string SegmentName { get; set; } = "";
using System.Text.RegularExpressions;
public static string SanitizeString(string input)
{
// Define a regular expression pattern to match allowed characters
string pattern = @"[^a-zA-Z0-9\s_\.\:/%&#=+\-@]";
// Replace any character that does not match the pattern with an empty string
return Regex.Replace(input, pattern, string.Empty);
}
Changes
📜 Documentation updates
- chore: Roadmap 2025 update (#757) by @hjgraca
- chore: Update docs Idempotency custom prefix (#758) by @hjgraca
- chore: Sync main with develop for release 1.20 (#752) by @hjgraca
- chore(deps): bump squidfunk/mkdocs-material from
7e841df
toc62453b
in /docs (#748) by @dependabot[bot] - chore: Add privacy plugin to mkdocs (#747) by @hjgraca
- chore: AOT support for Idempotency (#653) by @hjgraca
- chore(deps): bump squidfunk/mkdocs-material from
471695f
to7e841df
in /docs (#744) by @dependabot[bot] - chore(deps): bump squidfunk/mkdocs-material from
41942f7
to471695f
in /docs (#739) by @dependabot[bot]
🔧 Maintenance
- chore(deps): bump aws-actions/configure-aws-credentials from 4.0.3 to 4.1.0 (#755) by @dependabot[bot]
- chore(deps): bump actions/upload-artifact from 4.5.0 to 4.6.0 (#754) by @dependabot[bot]
- chore(deps): bump github/codeql-action from 3.27.9 to 3.28.9 (#753) by @dependabot[bot]
- chore: Roadmap 2025 update (#757) by @hjgraca
- chore: Update docs Idempotency custom prefix (#758) by @hjgraca
- chore: Sync main with develop for release 1.20 (#752) by @hjgraca
- chore: update versions for release 1.20 (#743) by @hjgraca
- chore(deps): bump pygments from 2.13.0 to 2.15.0 (#355) by @dependabot[bot]
- chore(deps): bump github/codeql-action from 3.28.8 to 3.28.9 (#751) by @dependabot[bot]
- chore(deps): bump zgosalvez/github-actions-ensure-sha-pinned-actions from 3.0.20 to 3.0.21 (#750) by @dependabot[bot]
- chore(deps): bump squidfunk/mkdocs-material from
7e841df
toc62453b
in /docs (#748) by @dependabot[bot] - chore: Add support for custom key prefixes in Idempotency utility (#745) by @hjgraca
- chore: Add privacy plugin to mkdocs (#747) by @hjgraca
- chore: AOT support for Idempotency (#653) by @hjgraca
- chore(deps): bump squidfunk/mkdocs-material from
471695f
to7e841df
in /docs (#744) by @dependabot[bot] - chore: idempotency e2e tests (#738) by @hjgraca
- chore: Tracing Sanitize SegmentName to avoid unsupported characters (#741) by @hjgraca
- chore(deps): bump squidfunk/mkdocs-material from
41942f7
to471695f
in /docs (#739) by @dependabot[bot] - chore(deps): bump actions/setup-dotnet from 4.2.0 to 4.3.0 (#736) by @dependabot[bot]
- chore(deps): bump github/codeql-action from 3.28.6 to 3.28.8 (#737) by @dependabot[bot]
- chore: Update api docs build to dotnet 8 (#734) by @hjgraca
- chore(deps): bump github/codeql-action from 3.28.5 to 3.28.6 (#727) by @dependabot[bot]
- chore(deps): bump aws-actions/configure-aws-credentials from 4.0.2 to 4.0.3 (#725) by @dependabot[bot]
- chore(deps): bump actions/setup-python from 5.3.0 to 5.4.0 (#726) by @dependabot[bot]
- chore: Update test projects to no be packable (#731) by @hjgraca
This release was made possible by the following contributors:
@dependabot[bot], @hjgraca and dependabot[bot]