From 668ae51f38ff6822c1b561e356a5eb3940f7070f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=F0=9F=9A=80=20Jack?= Date: Sat, 14 Oct 2023 11:50:18 +1100 Subject: [PATCH] feat(type-safe-api): enable snapstart for java handlers by default and optimise java interceptors Java handlers now have snapstart enabled by default to improve cold start times. Ensure logger, metrics and tracer perform as much initialisation as possible during the init phase which can therefore be saved from snapstart invocations. Fixes #572 --- .../templates/functions.handlebars | 6 +- .../templates/handlers.handlebars | 7 +- .../java/templates/handlers.mustache | 8 +- .../java/templates/interceptors.mustache | 11 +- .../templates/functions.handlebars | 3 +- .../templates/functions.handlebars | 5 +- .../src/construct/functions/index.ts | 3 + .../functions/snap-start-java-function.ts | 30 +++++ packages/type-safe-api/src/construct/index.ts | 1 + .../src/construct/integrations/lambda.ts | 8 +- .../java-cdk-infrastructure.test.ts.snap | 20 +++- .../java-lambda-handlers.test.ts.snap | 14 ++- .../__snapshots__/java.test.ts.snap | 110 ++++++++++++------ .../python-cdk-infrastructure.test.ts.snap | 5 +- ...typescript-cdk-infrastructure.test.ts.snap | 9 +- 15 files changed, 179 insertions(+), 61 deletions(-) create mode 100644 packages/type-safe-api/src/construct/functions/index.ts create mode 100644 packages/type-safe-api/src/construct/functions/snap-start-java-function.ts diff --git a/packages/type-safe-api/scripts/type-safe-api/generators/java-cdk-infrastructure/templates/functions.handlebars b/packages/type-safe-api/scripts/type-safe-api/generators/java-cdk-infrastructure/templates/functions.handlebars index ff6e799ec..7aa051830 100644 --- a/packages/type-safe-api/scripts/type-safe-api/generators/java-cdk-infrastructure/templates/functions.handlebars +++ b/packages/type-safe-api/scripts/type-safe-api/generators/java-cdk-infrastructure/templates/functions.handlebars @@ -15,12 +15,13 @@ import org.jetbrains.annotations.NotNull; import software.amazon.awscdk.services.lambda.Function; +import software.aws.pdk.type_safe_api.SnapStartFunction; import software.constructs.Construct; /** * Lambda function construct which points to the {{vendorExtensions.x-handler.language}} implementation of {{operationIdCamelCase}} */ -public class {{operationIdCamelCase}}Function extends Function { +public class {{operationIdCamelCase}}Function extends {{#startsWith vendorExtensions.x-handler.language 'java' ~}}SnapStart{{~/startsWith}}Function { public {{operationIdCamelCase}}Function(@NotNull Construct scope, @NotNull String id, @NotNull {{operationIdCamelCase}}FunctionProps props) { super(scope, id, props); } @@ -67,6 +68,7 @@ import software.amazon.awscdk.services.lambda.VersionOptions; import software.amazon.awscdk.services.logs.RetentionDays; import software.amazon.awscdk.services.sns.ITopic; import software.amazon.awscdk.services.sqs.IQueue; +import software.aws.pdk.type_safe_api.SnapStartFunctionProps; import java.io.BufferedReader; import java.io.IOException; @@ -77,7 +79,7 @@ import java.util.List; import java.util.Map; @lombok.Builder @lombok.Getter -public class {{operationIdCamelCase}}FunctionProps implements FunctionProps { +public class {{operationIdCamelCase}}FunctionProps implements {{#startsWith vendorExtensions.x-handler.language 'java' ~}}SnapStart{{~/startsWith}}FunctionProps { private static String infraProjectAbsolutePath; static { diff --git a/packages/type-safe-api/scripts/type-safe-api/generators/java-lambda-handlers/templates/handlers.handlebars b/packages/type-safe-api/scripts/type-safe-api/generators/java-lambda-handlers/templates/handlers.handlebars index 9ca92e6da..70370e911 100644 --- a/packages/type-safe-api/scripts/type-safe-api/generators/java-lambda-handlers/templates/handlers.handlebars +++ b/packages/type-safe-api/scripts/type-safe-api/generators/java-lambda-handlers/templates/handlers.handlebars @@ -31,13 +31,18 @@ import java.util.List; * The {{operationIdCamelCase}} class manages marshalling inputs and outputs. */ public class {{operationIdCamelCase}}Handler extends {{operationIdCamelCase}} { + /** + * Interceptors are initialised once during the lambda "init" phase + */ + private final List> interceptors = DefaultInterceptors.all(); + /** * Return the interceptors for this handler. * You can also use the @Interceptors annotation on the class to add interceptors */ @Override public List> getInterceptors() { - return DefaultInterceptors.all(); + return this.interceptors; } /** diff --git a/packages/type-safe-api/scripts/type-safe-api/generators/java/templates/handlers.mustache b/packages/type-safe-api/scripts/type-safe-api/generators/java/templates/handlers.mustache index a84e206b8..334ce391f 100644 --- a/packages/type-safe-api/scripts/type-safe-api/generators/java/templates/handlers.mustache +++ b/packages/type-safe-api/scripts/type-safe-api/generators/java/templates/handlers.mustache @@ -1023,6 +1023,11 @@ public abstract class {{operationIdCamelCase}} implements RequestHandler> annotationInterceptors = Handlers.getAnnotationInterceptors({{operationIdCamelCase}}.class); + /** * For more complex interceptors that require instantiation with parameters, you may override this method to * return a list of instantiated interceptors. For simple interceptors with no need for constructor arguments, @@ -1055,9 +1060,6 @@ public abstract class {{operationIdCamelCase}} implements RequestHandler> interceptors = new ArrayList<>(); interceptors.addAll(additionalInterceptors); - - List> annotationInterceptors = Handlers.getAnnotationInterceptors(this.getClass()); - interceptors.addAll(annotationInterceptors); interceptors.addAll(this.getInterceptors()); diff --git a/packages/type-safe-api/scripts/type-safe-api/generators/java/templates/interceptors.mustache b/packages/type-safe-api/scripts/type-safe-api/generators/java/templates/interceptors.mustache index 6151031d9..ed20ca6db 100644 --- a/packages/type-safe-api/scripts/type-safe-api/generators/java/templates/interceptors.mustache +++ b/packages/type-safe-api/scripts/type-safe-api/generators/java/templates/interceptors.mustache @@ -123,6 +123,7 @@ import software.amazon.lambda.powertools.logging.LoggingUtils; * See https://docs.powertools.aws.dev/lambda/java/latest/core/logging/ */ public class LoggingInterceptor implements Interceptor { + private Logger logger = LogManager.getLogger(LoggingInterceptor.class); /** * Return the instance of the logger from the interceptor context @@ -161,7 +162,6 @@ public class LoggingInterceptor implements Interceptor { LoggingUtils.appendKey("operationId", operationId); // Add the logger to the interceptor context - Logger logger = LogManager.getLogger(operationId); input.getInterceptorContext().put("logger", logger); Response response = input.getChain().next(input); @@ -202,6 +202,13 @@ import software.amazon.lambda.powertools.tracing.TracingUtils; */ public class TracingInterceptor implements Interceptor { + { + // Create a segment during the lambda init phase to ensure xray emitter + // is warmed up prior to invocation phase + AWSXRay.beginSubsegment("Tracing Interceptor - Init"); + AWSXRay.endSubsegment(); + } + private final boolean captureResponse; public TracingInterceptor(final boolean captureResponse) { @@ -284,6 +291,7 @@ import software.amazon.lambda.powertools.metrics.MetricsUtils; * See: https://docs.powertools.aws.dev/lambda/typescript/latest/core/metrics */ public class MetricsInterceptor implements Interceptor { + private MetricsLogger metrics = MetricsUtils.metricsLogger(); /** * Return the instance of the metrics logger from the interceptor context @@ -298,7 +306,6 @@ public class MetricsInterceptor implements Interceptor { @Override public Response handle(final ChainedRequestInput input) { - MetricsLogger metrics = MetricsUtils.metricsLogger(); metrics.putDimensions(DimensionSet.of("operationId", (String) input.getInterceptorContext().get("operationId"))); input.getInterceptorContext().put("metrics", metrics); diff --git a/packages/type-safe-api/scripts/type-safe-api/generators/python-cdk-infrastructure/templates/functions.handlebars b/packages/type-safe-api/scripts/type-safe-api/generators/python-cdk-infrastructure/templates/functions.handlebars index 4bb231297..a78f6e321 100644 --- a/packages/type-safe-api/scripts/type-safe-api/generators/python-cdk-infrastructure/templates/functions.handlebars +++ b/packages/type-safe-api/scripts/type-safe-api/generators/python-cdk-infrastructure/templates/functions.handlebars @@ -10,6 +10,7 @@ from aws_cdk.aws_lambda import ( Function, Runtime, Tracing, Code ) +from aws_pdk.type_safe_api import SnapStartFunction from os import path from pathlib import Path @@ -19,7 +20,7 @@ from pathlib import Path {{#operation ~}} {{#if vendorExtensions.x-handler}} -class {{operationIdCamelCase}}Function(Function): +class {{operationIdCamelCase}}Function({{#startsWith vendorExtensions.x-handler.language 'java' ~}}SnapStart{{~/startsWith}}Function): """ Lambda function construct which points to the {{vendorExtensions.x-handler.language}} implementation of {{operationIdCamelCase}} """ diff --git a/packages/type-safe-api/scripts/type-safe-api/generators/typescript-cdk-infrastructure/templates/functions.handlebars b/packages/type-safe-api/scripts/type-safe-api/generators/typescript-cdk-infrastructure/templates/functions.handlebars index 825ed10ba..bb9bca4d0 100644 --- a/packages/type-safe-api/scripts/type-safe-api/generators/typescript-cdk-infrastructure/templates/functions.handlebars +++ b/packages/type-safe-api/scripts/type-safe-api/generators/typescript-cdk-infrastructure/templates/functions.handlebars @@ -9,6 +9,7 @@ } ###/TSAPI_WRITE_FILE###import { Construct } from "constructs"; import { Duration } from "aws-cdk-lib"; +import { SnapStartFunction, SnapStartFunctionProps } from "@aws/pdk/type-safe-api"; import { Code, Function, Runtime, Tracing, FunctionProps } from "aws-cdk-lib/aws-lambda"; import * as path from "path"; {{#apiInfo ~}} @@ -20,12 +21,12 @@ import * as path from "path"; /** * Options for the {{operationIdCamelCase}}Function construct */ -export interface {{operationIdCamelCase}}FunctionProps extends Omit {} +export interface {{operationIdCamelCase}}FunctionProps extends Omit<{{#startsWith vendorExtensions.x-handler.language 'java' ~}}SnapStart{{~/startsWith}}FunctionProps, 'code' | 'handler' | 'runtime'> {} /** * Lambda function construct which points to the {{vendorExtensions.x-handler.language}} implementation of {{operationIdCamelCase}} */ -export class {{operationIdCamelCase}}Function extends Function { +export class {{operationIdCamelCase}}Function extends {{#startsWith vendorExtensions.x-handler.language 'java' ~}}SnapStart{{~/startsWith}}Function { constructor(scope: Construct, id: string, props?: {{operationIdCamelCase}}FunctionProps) { super(scope, id, { {{#startsWith vendorExtensions.x-handler.language 'typescript' ~}} diff --git a/packages/type-safe-api/src/construct/functions/index.ts b/packages/type-safe-api/src/construct/functions/index.ts new file mode 100644 index 000000000..d790a4590 --- /dev/null +++ b/packages/type-safe-api/src/construct/functions/index.ts @@ -0,0 +1,3 @@ +/*! Copyright [Amazon.com](http://amazon.com/), Inc. or its affiliates. All Rights Reserved. +SPDX-License-Identifier: Apache-2.0 */ +export * from "./snap-start-java-function"; diff --git a/packages/type-safe-api/src/construct/functions/snap-start-java-function.ts b/packages/type-safe-api/src/construct/functions/snap-start-java-function.ts new file mode 100644 index 000000000..6d49b3751 --- /dev/null +++ b/packages/type-safe-api/src/construct/functions/snap-start-java-function.ts @@ -0,0 +1,30 @@ +/*! Copyright [Amazon.com](http://amazon.com/), Inc. or its affiliates. All Rights Reserved. +SPDX-License-Identifier: Apache-2.0 */ +import { CfnFunction, Function, FunctionProps } from "aws-cdk-lib/aws-lambda"; +import { Construct } from "constructs"; + +/** + * Options for the SnapStartFunction construct + */ +export interface SnapStartFunctionProps extends FunctionProps { + /** + * When true, disable snap start + * @default false + */ + readonly disableSnapStart?: boolean; +} + +/** + * A lambda function which enables SnapStart on published versions by default + */ +export class SnapStartFunction extends Function { + constructor(scope: Construct, id: string, props: SnapStartFunctionProps) { + super(scope, id, props); + + if (!props.disableSnapStart) { + (this.node.defaultChild as CfnFunction).addPropertyOverride("SnapStart", { + ApplyOn: "PublishedVersions", + }); + } + } +} diff --git a/packages/type-safe-api/src/construct/index.ts b/packages/type-safe-api/src/construct/index.ts index cbd5f2902..bb4d2c50b 100644 --- a/packages/type-safe-api/src/construct/index.ts +++ b/packages/type-safe-api/src/construct/index.ts @@ -5,3 +5,4 @@ export * from "./waf/types"; export * from "./authorizers"; export * from "./integrations"; export * from "./spec"; +export * from "./functions"; diff --git a/packages/type-safe-api/src/construct/integrations/lambda.ts b/packages/type-safe-api/src/construct/integrations/lambda.ts index 11f4ebe85..837ee404c 100644 --- a/packages/type-safe-api/src/construct/integrations/lambda.ts +++ b/packages/type-safe-api/src/construct/integrations/lambda.ts @@ -8,6 +8,7 @@ import { IntegrationGrantProps, IntegrationRenderProps, } from "./integration"; +import { SnapStartFunction } from "../functions/snap-start-java-function"; import { functionInvocationUri } from "../spec/utils"; /** @@ -18,7 +19,12 @@ export class LambdaIntegration extends Integration { constructor(lambdaFunction: IFunction) { super(); - this.lambdaFunction = lambdaFunction; + // Snap Start applies only to versions, so if the function is a SnapStartFunction, we'll reference the current version + if (lambdaFunction instanceof SnapStartFunction) { + this.lambdaFunction = lambdaFunction.currentVersion; + } else { + this.lambdaFunction = lambdaFunction; + } } /** diff --git a/packages/type-safe-api/test/scripts/generators/__snapshots__/java-cdk-infrastructure.test.ts.snap b/packages/type-safe-api/test/scripts/generators/__snapshots__/java-cdk-infrastructure.test.ts.snap index 774f63ea5..1b9d46a7d 100644 --- a/packages/type-safe-api/test/scripts/generators/__snapshots__/java-cdk-infrastructure.test.ts.snap +++ b/packages/type-safe-api/test/scripts/generators/__snapshots__/java-cdk-infrastructure.test.ts.snap @@ -8,12 +8,13 @@ exports[`Java Infrastructure Code Generation Script Unit Tests Generates Functio import org.jetbrains.annotations.NotNull; import software.amazon.awscdk.services.lambda.Function; +import software.aws.pdk.type_safe_api.SnapStartFunction; import software.constructs.Construct; /** * Lambda function construct which points to the java implementation of JavaOne */ -public class JavaOneFunction extends Function { +public class JavaOneFunction extends SnapStartFunction { public JavaOneFunction(@NotNull Construct scope, @NotNull String id, @NotNull JavaOneFunctionProps props) { super(scope, id, props); } @@ -57,6 +58,7 @@ import software.amazon.awscdk.services.lambda.VersionOptions; import software.amazon.awscdk.services.logs.RetentionDays; import software.amazon.awscdk.services.sns.ITopic; import software.amazon.awscdk.services.sqs.IQueue; +import software.aws.pdk.type_safe_api.SnapStartFunctionProps; import java.io.BufferedReader; import java.io.IOException; @@ -67,7 +69,7 @@ import java.util.List; import java.util.Map; @lombok.Builder @lombok.Getter -public class JavaOneFunctionProps implements FunctionProps { +public class JavaOneFunctionProps implements SnapStartFunctionProps { private static String infraProjectAbsolutePath; static { @@ -144,12 +146,13 @@ public class JavaOneFunctionProps implements FunctionProps { import org.jetbrains.annotations.NotNull; import software.amazon.awscdk.services.lambda.Function; +import software.aws.pdk.type_safe_api.SnapStartFunction; import software.constructs.Construct; /** * Lambda function construct which points to the java implementation of JavaTwo */ -public class JavaTwoFunction extends Function { +public class JavaTwoFunction extends SnapStartFunction { public JavaTwoFunction(@NotNull Construct scope, @NotNull String id, @NotNull JavaTwoFunctionProps props) { super(scope, id, props); } @@ -193,6 +196,7 @@ import software.amazon.awscdk.services.lambda.VersionOptions; import software.amazon.awscdk.services.logs.RetentionDays; import software.amazon.awscdk.services.sns.ITopic; import software.amazon.awscdk.services.sqs.IQueue; +import software.aws.pdk.type_safe_api.SnapStartFunctionProps; import java.io.BufferedReader; import java.io.IOException; @@ -203,7 +207,7 @@ import java.util.List; import java.util.Map; @lombok.Builder @lombok.Getter -public class JavaTwoFunctionProps implements FunctionProps { +public class JavaTwoFunctionProps implements SnapStartFunctionProps { private static String infraProjectAbsolutePath; static { @@ -280,6 +284,7 @@ public class JavaTwoFunctionProps implements FunctionProps { import org.jetbrains.annotations.NotNull; import software.amazon.awscdk.services.lambda.Function; +import software.aws.pdk.type_safe_api.SnapStartFunction; import software.constructs.Construct; /** @@ -329,6 +334,7 @@ import software.amazon.awscdk.services.lambda.VersionOptions; import software.amazon.awscdk.services.logs.RetentionDays; import software.amazon.awscdk.services.sns.ITopic; import software.amazon.awscdk.services.sqs.IQueue; +import software.aws.pdk.type_safe_api.SnapStartFunctionProps; import java.io.BufferedReader; import java.io.IOException; @@ -416,6 +422,7 @@ public class PythonOneFunctionProps implements FunctionProps { import org.jetbrains.annotations.NotNull; import software.amazon.awscdk.services.lambda.Function; +import software.aws.pdk.type_safe_api.SnapStartFunction; import software.constructs.Construct; /** @@ -465,6 +472,7 @@ import software.amazon.awscdk.services.lambda.VersionOptions; import software.amazon.awscdk.services.logs.RetentionDays; import software.amazon.awscdk.services.sns.ITopic; import software.amazon.awscdk.services.sqs.IQueue; +import software.aws.pdk.type_safe_api.SnapStartFunctionProps; import java.io.BufferedReader; import java.io.IOException; @@ -552,6 +560,7 @@ public class PythonTwoFunctionProps implements FunctionProps { import org.jetbrains.annotations.NotNull; import software.amazon.awscdk.services.lambda.Function; +import software.aws.pdk.type_safe_api.SnapStartFunction; import software.constructs.Construct; /** @@ -601,6 +610,7 @@ import software.amazon.awscdk.services.lambda.VersionOptions; import software.amazon.awscdk.services.logs.RetentionDays; import software.amazon.awscdk.services.sns.ITopic; import software.amazon.awscdk.services.sqs.IQueue; +import software.aws.pdk.type_safe_api.SnapStartFunctionProps; import java.io.BufferedReader; import java.io.IOException; @@ -688,6 +698,7 @@ public class TypescriptOneFunctionProps implements FunctionProps { import org.jetbrains.annotations.NotNull; import software.amazon.awscdk.services.lambda.Function; +import software.aws.pdk.type_safe_api.SnapStartFunction; import software.constructs.Construct; /** @@ -737,6 +748,7 @@ import software.amazon.awscdk.services.lambda.VersionOptions; import software.amazon.awscdk.services.logs.RetentionDays; import software.amazon.awscdk.services.sns.ITopic; import software.amazon.awscdk.services.sqs.IQueue; +import software.aws.pdk.type_safe_api.SnapStartFunctionProps; import java.io.BufferedReader; import java.io.IOException; diff --git a/packages/type-safe-api/test/scripts/generators/__snapshots__/java-lambda-handlers.test.ts.snap b/packages/type-safe-api/test/scripts/generators/__snapshots__/java-lambda-handlers.test.ts.snap index 64d2d5b1f..3666e375a 100644 --- a/packages/type-safe-api/test/scripts/generators/__snapshots__/java-lambda-handlers.test.ts.snap +++ b/packages/type-safe-api/test/scripts/generators/__snapshots__/java-lambda-handlers.test.ts.snap @@ -20,13 +20,18 @@ import java.util.List; * The JavaOne class manages marshalling inputs and outputs. */ public class JavaOneHandler extends JavaOne { + /** + * Interceptors are initialised once during the lambda "init" phase + */ + private final List> interceptors = DefaultInterceptors.all(); + /** * Return the interceptors for this handler. * You can also use the @Interceptors annotation on the class to add interceptors */ @Override public List> getInterceptors() { - return DefaultInterceptors.all(); + return this.interceptors; } /** @@ -68,13 +73,18 @@ import java.util.List; * The JavaTwo class manages marshalling inputs and outputs. */ public class JavaTwoHandler extends JavaTwo { + /** + * Interceptors are initialised once during the lambda "init" phase + */ + private final List> interceptors = DefaultInterceptors.all(); + /** * Return the interceptors for this handler. * You can also use the @Interceptors annotation on the class to add interceptors */ @Override public List> getInterceptors() { - return DefaultInterceptors.all(); + return this.interceptors; } /** diff --git a/packages/type-safe-api/test/scripts/generators/__snapshots__/java.test.ts.snap b/packages/type-safe-api/test/scripts/generators/__snapshots__/java.test.ts.snap index 43f2f97e8..cd138506c 100644 --- a/packages/type-safe-api/test/scripts/generators/__snapshots__/java.test.ts.snap +++ b/packages/type-safe-api/test/scripts/generators/__snapshots__/java.test.ts.snap @@ -4824,6 +4824,11 @@ public abstract class Both implements RequestHandler> annotationInterceptors = Handlers.getAnnotationInterceptors(Both.class); + /** * For more complex interceptors that require instantiation with parameters, you may override this method to * return a list of instantiated interceptors. For simple interceptors with no need for constructor arguments, @@ -4849,9 +4854,6 @@ public abstract class Both implements RequestHandler> interceptors = new ArrayList<>(); interceptors.addAll(additionalInterceptors); - - List> annotationInterceptors = Handlers.getAnnotationInterceptors(this.getClass()); - interceptors.addAll(annotationInterceptors); interceptors.addAll(this.getInterceptors()); @@ -5144,6 +5146,11 @@ public abstract class Neither implements RequestHandler> annotationInterceptors = Handlers.getAnnotationInterceptors(Neither.class); + /** * For more complex interceptors that require instantiation with parameters, you may override this method to * return a list of instantiated interceptors. For simple interceptors with no need for constructor arguments, @@ -5169,9 +5176,6 @@ public abstract class Neither implements RequestHandler> interceptors = new ArrayList<>(); interceptors.addAll(additionalInterceptors); - - List> annotationInterceptors = Handlers.getAnnotationInterceptors(this.getClass()); - interceptors.addAll(annotationInterceptors); interceptors.addAll(this.getInterceptors()); @@ -5464,6 +5468,11 @@ public abstract class Tag1 implements RequestHandler> annotationInterceptors = Handlers.getAnnotationInterceptors(Tag1.class); + /** * For more complex interceptors that require instantiation with parameters, you may override this method to * return a list of instantiated interceptors. For simple interceptors with no need for constructor arguments, @@ -5489,9 +5498,6 @@ public abstract class Tag1 implements RequestHandler> interceptors = new ArrayList<>(); interceptors.addAll(additionalInterceptors); - - List> annotationInterceptors = Handlers.getAnnotationInterceptors(this.getClass()); - interceptors.addAll(annotationInterceptors); interceptors.addAll(this.getInterceptors()); @@ -5784,6 +5790,11 @@ public abstract class Tag2 implements RequestHandler> annotationInterceptors = Handlers.getAnnotationInterceptors(Tag2.class); + /** * For more complex interceptors that require instantiation with parameters, you may override this method to * return a list of instantiated interceptors. For simple interceptors with no need for constructor arguments, @@ -5809,9 +5820,6 @@ public abstract class Tag2 implements RequestHandler> interceptors = new ArrayList<>(); interceptors.addAll(additionalInterceptors); - - List> annotationInterceptors = Handlers.getAnnotationInterceptors(this.getClass()); - interceptors.addAll(annotationInterceptors); interceptors.addAll(this.getInterceptors()); @@ -6199,6 +6207,7 @@ import software.amazon.lambda.powertools.logging.LoggingUtils; * See https://docs.powertools.aws.dev/lambda/java/latest/core/logging/ */ public class LoggingInterceptor implements Interceptor { + private Logger logger = LogManager.getLogger(LoggingInterceptor.class); /** * Return the instance of the logger from the interceptor context @@ -6237,7 +6246,6 @@ public class LoggingInterceptor implements Interceptor { LoggingUtils.appendKey("operationId", operationId); // Add the logger to the interceptor context - Logger logger = LogManager.getLogger(operationId); input.getInterceptorContext().put("logger", logger); Response response = input.getChain().next(input); @@ -6269,6 +6277,7 @@ import software.amazon.lambda.powertools.metrics.MetricsUtils; * See: https://docs.powertools.aws.dev/lambda/typescript/latest/core/metrics */ public class MetricsInterceptor implements Interceptor { + private MetricsLogger metrics = MetricsUtils.metricsLogger(); /** * Return the instance of the metrics logger from the interceptor context @@ -6283,7 +6292,6 @@ public class MetricsInterceptor implements Interceptor { @Override public Response handle(final ChainedRequestInput input) { - MetricsLogger metrics = MetricsUtils.metricsLogger(); metrics.putDimensions(DimensionSet.of("operationId", (String) input.getInterceptorContext().get("operationId"))); input.getInterceptorContext().put("metrics", metrics); @@ -6326,6 +6334,13 @@ import software.amazon.lambda.powertools.tracing.TracingUtils; */ public class TracingInterceptor implements Interceptor { + { + // Create a segment during the lambda init phase to ensure xray emitter + // is warmed up prior to invocation phase + AWSXRay.beginSubsegment("Tracing Interceptor - Init"); + AWSXRay.endSubsegment(); + } + private final boolean captureResponse; public TracingInterceptor(final boolean captureResponse) { @@ -12683,6 +12698,11 @@ public abstract class AnyRequestResponse implements RequestHandler> annotationInterceptors = Handlers.getAnnotationInterceptors(AnyRequestResponse.class); + /** * For more complex interceptors that require instantiation with parameters, you may override this method to * return a list of instantiated interceptors. For simple interceptors with no need for constructor arguments, @@ -12708,9 +12728,6 @@ public abstract class AnyRequestResponse implements RequestHandler> interceptors = new ArrayList<>(); interceptors.addAll(additionalInterceptors); - - List> annotationInterceptors = Handlers.getAnnotationInterceptors(this.getClass()); - interceptors.addAll(annotationInterceptors); interceptors.addAll(this.getInterceptors()); @@ -13011,6 +13028,11 @@ public abstract class Empty implements RequestHandler> annotationInterceptors = Handlers.getAnnotationInterceptors(Empty.class); + /** * For more complex interceptors that require instantiation with parameters, you may override this method to * return a list of instantiated interceptors. For simple interceptors with no need for constructor arguments, @@ -13036,9 +13058,6 @@ public abstract class Empty implements RequestHandler> interceptors = new ArrayList<>(); interceptors.addAll(additionalInterceptors); - - List> annotationInterceptors = Handlers.getAnnotationInterceptors(this.getClass()); - interceptors.addAll(annotationInterceptors); interceptors.addAll(this.getInterceptors()); @@ -13331,6 +13350,11 @@ public abstract class MapResponse implements RequestHandler> annotationInterceptors = Handlers.getAnnotationInterceptors(MapResponse.class); + /** * For more complex interceptors that require instantiation with parameters, you may override this method to * return a list of instantiated interceptors. For simple interceptors with no need for constructor arguments, @@ -13356,9 +13380,6 @@ public abstract class MapResponse implements RequestHandler> interceptors = new ArrayList<>(); interceptors.addAll(additionalInterceptors); - - List> annotationInterceptors = Handlers.getAnnotationInterceptors(this.getClass()); - interceptors.addAll(annotationInterceptors); interceptors.addAll(this.getInterceptors()); @@ -13654,6 +13675,11 @@ public abstract class MediaTypes implements RequestHandler> annotationInterceptors = Handlers.getAnnotationInterceptors(MediaTypes.class); + /** * For more complex interceptors that require instantiation with parameters, you may override this method to * return a list of instantiated interceptors. For simple interceptors with no need for constructor arguments, @@ -13679,9 +13705,6 @@ public abstract class MediaTypes implements RequestHandler> interceptors = new ArrayList<>(); interceptors.addAll(additionalInterceptors); - - List> annotationInterceptors = Handlers.getAnnotationInterceptors(this.getClass()); - interceptors.addAll(annotationInterceptors); interceptors.addAll(this.getInterceptors()); @@ -13982,6 +14005,11 @@ public abstract class MultipleContentTypes implements RequestHandler> annotationInterceptors = Handlers.getAnnotationInterceptors(MultipleContentTypes.class); + /** * For more complex interceptors that require instantiation with parameters, you may override this method to * return a list of instantiated interceptors. For simple interceptors with no need for constructor arguments, @@ -14007,9 +14035,6 @@ public abstract class MultipleContentTypes implements RequestHandler> interceptors = new ArrayList<>(); interceptors.addAll(additionalInterceptors); - - List> annotationInterceptors = Handlers.getAnnotationInterceptors(this.getClass()); - interceptors.addAll(annotationInterceptors); interceptors.addAll(this.getInterceptors()); @@ -14314,6 +14339,11 @@ public abstract class OperationOne implements RequestHandler> annotationInterceptors = Handlers.getAnnotationInterceptors(OperationOne.class); + /** * For more complex interceptors that require instantiation with parameters, you may override this method to * return a list of instantiated interceptors. For simple interceptors with no need for constructor arguments, @@ -14342,9 +14372,6 @@ public abstract class OperationOne implements RequestHandler> interceptors = new ArrayList<>(); interceptors.addAll(additionalInterceptors); - - List> annotationInterceptors = Handlers.getAnnotationInterceptors(this.getClass()); - interceptors.addAll(annotationInterceptors); interceptors.addAll(this.getInterceptors()); @@ -14746,6 +14773,11 @@ public abstract class WithoutOperationIdDelete implements RequestHandler> annotationInterceptors = Handlers.getAnnotationInterceptors(WithoutOperationIdDelete.class); + /** * For more complex interceptors that require instantiation with parameters, you may override this method to * return a list of instantiated interceptors. For simple interceptors with no need for constructor arguments, @@ -14771,9 +14803,6 @@ public abstract class WithoutOperationIdDelete implements RequestHandler> interceptors = new ArrayList<>(); interceptors.addAll(additionalInterceptors); - - List> annotationInterceptors = Handlers.getAnnotationInterceptors(this.getClass()); - interceptors.addAll(annotationInterceptors); interceptors.addAll(this.getInterceptors()); @@ -15164,6 +15193,7 @@ import software.amazon.lambda.powertools.logging.LoggingUtils; * See https://docs.powertools.aws.dev/lambda/java/latest/core/logging/ */ public class LoggingInterceptor implements Interceptor { + private Logger logger = LogManager.getLogger(LoggingInterceptor.class); /** * Return the instance of the logger from the interceptor context @@ -15202,7 +15232,6 @@ public class LoggingInterceptor implements Interceptor { LoggingUtils.appendKey("operationId", operationId); // Add the logger to the interceptor context - Logger logger = LogManager.getLogger(operationId); input.getInterceptorContext().put("logger", logger); Response response = input.getChain().next(input); @@ -15234,6 +15263,7 @@ import software.amazon.lambda.powertools.metrics.MetricsUtils; * See: https://docs.powertools.aws.dev/lambda/typescript/latest/core/metrics */ public class MetricsInterceptor implements Interceptor { + private MetricsLogger metrics = MetricsUtils.metricsLogger(); /** * Return the instance of the metrics logger from the interceptor context @@ -15248,7 +15278,6 @@ public class MetricsInterceptor implements Interceptor { @Override public Response handle(final ChainedRequestInput input) { - MetricsLogger metrics = MetricsUtils.metricsLogger(); metrics.putDimensions(DimensionSet.of("operationId", (String) input.getInterceptorContext().get("operationId"))); input.getInterceptorContext().put("metrics", metrics); @@ -15291,6 +15320,13 @@ import software.amazon.lambda.powertools.tracing.TracingUtils; */ public class TracingInterceptor implements Interceptor { + { + // Create a segment during the lambda init phase to ensure xray emitter + // is warmed up prior to invocation phase + AWSXRay.beginSubsegment("Tracing Interceptor - Init"); + AWSXRay.endSubsegment(); + } + private final boolean captureResponse; public TracingInterceptor(final boolean captureResponse) { diff --git a/packages/type-safe-api/test/scripts/generators/__snapshots__/python-cdk-infrastructure.test.ts.snap b/packages/type-safe-api/test/scripts/generators/__snapshots__/python-cdk-infrastructure.test.ts.snap index 71e23f76a..d034b31a9 100644 --- a/packages/type-safe-api/test/scripts/generators/__snapshots__/python-cdk-infrastructure.test.ts.snap +++ b/packages/type-safe-api/test/scripts/generators/__snapshots__/python-cdk-infrastructure.test.ts.snap @@ -5,12 +5,13 @@ exports[`Python Infrastructure Code Generation Script Unit Tests Generates Funct from aws_cdk.aws_lambda import ( Function, Runtime, Tracing, Code ) +from aws_pdk.type_safe_api import SnapStartFunction from os import path from pathlib import Path -class JavaOneFunction(Function): +class JavaOneFunction(SnapStartFunction): """ Lambda function construct which points to the java implementation of JavaOne """ @@ -26,7 +27,7 @@ class JavaOneFunction(Function): **kwargs, ) -class JavaTwoFunction(Function): +class JavaTwoFunction(SnapStartFunction): """ Lambda function construct which points to the java implementation of JavaTwo """ diff --git a/packages/type-safe-api/test/scripts/generators/__snapshots__/typescript-cdk-infrastructure.test.ts.snap b/packages/type-safe-api/test/scripts/generators/__snapshots__/typescript-cdk-infrastructure.test.ts.snap index 70649a03f..d3ed2cad5 100644 --- a/packages/type-safe-api/test/scripts/generators/__snapshots__/typescript-cdk-infrastructure.test.ts.snap +++ b/packages/type-safe-api/test/scripts/generators/__snapshots__/typescript-cdk-infrastructure.test.ts.snap @@ -3,6 +3,7 @@ exports[`Typescript Infrastructure Code Generation Script Unit Tests Generates Functions 1`] = ` "import { Construct } from "constructs"; import { Duration } from "aws-cdk-lib"; +import { SnapStartFunction, SnapStartFunctionProps } from "@aws/pdk/type-safe-api"; import { Code, Function, Runtime, Tracing, FunctionProps } from "aws-cdk-lib/aws-lambda"; import * as path from "path"; @@ -10,12 +11,12 @@ import * as path from "path"; /** * Options for the JavaOneFunction construct */ -export interface JavaOneFunctionProps extends Omit {} +export interface JavaOneFunctionProps extends Omit {} /** * Lambda function construct which points to the java implementation of JavaOne */ -export class JavaOneFunction extends Function { +export class JavaOneFunction extends SnapStartFunction { constructor(scope: Construct, id: string, props?: JavaOneFunctionProps) { super(scope, id, { runtime: Runtime.JAVA_17, @@ -33,12 +34,12 @@ export class JavaOneFunction extends Function { /** * Options for the JavaTwoFunction construct */ -export interface JavaTwoFunctionProps extends Omit {} +export interface JavaTwoFunctionProps extends Omit {} /** * Lambda function construct which points to the java implementation of JavaTwo */ -export class JavaTwoFunction extends Function { +export class JavaTwoFunction extends SnapStartFunction { constructor(scope: Construct, id: string, props?: JavaTwoFunctionProps) { super(scope, id, { runtime: Runtime.JAVA_17,