From 2995cad1972707f3682f87c6c8a854c9cf47b73b Mon Sep 17 00:00:00 2001 From: Andrea Amorosi Date: Thu, 13 Mar 2025 16:39:57 +0100 Subject: [PATCH 1/6] feat(commons): make utilities aware of provisioned concurrency --- packages/commons/src/Utility.ts | 28 +++++++++++++++ packages/commons/tests/unit/Utility.test.ts | 34 +++++++++++++++++++ .../commons/tests/unit/awsSdkUtils.test.ts | 4 +++ packages/commons/vitest.config.ts | 1 + 4 files changed, 67 insertions(+) diff --git a/packages/commons/src/Utility.ts b/packages/commons/src/Utility.ts index 2932785e0d..d43edc0ebf 100644 --- a/packages/commons/src/Utility.ts +++ b/packages/commons/src/Utility.ts @@ -51,15 +51,43 @@ * ``` */ export class Utility { + #initializationType: 'unknown' | 'on-demand' | 'provisioned-concurrency'; protected coldStart = true; protected readonly defaultServiceName: string = 'service_undefined'; + public constructor() { + this.#initializationType = this.getInitializationType(); + if (this.#initializationType !== 'on-demand') { + this.coldStart = false; + } + } + + /** + * Get the value of the `POWERTOOLS_SERVICE_NAME` environment variable. + */ + protected getInitializationType(): + | 'unknown' + | 'on-demand' + | 'provisioned-concurrency' { + const envVarValue = process.env.AWS_LAMBDA_INITIALIZATION_TYPE?.trim(); + if (envVarValue === 'on-demand') { + return 'on-demand'; + } + if (envVarValue === 'provisioned-concurrency') { + return 'provisioned-concurrency'; + } + return 'unknown'; + } + /** * Get the cold start status of the current execution environment. * * The method also flips the cold start status to `false` after the first invocation. */ protected getColdStart(): boolean { + if (this.#initializationType !== 'on-demand') { + return false; + } if (this.coldStart) { this.coldStart = false; diff --git a/packages/commons/tests/unit/Utility.test.ts b/packages/commons/tests/unit/Utility.test.ts index 16f88c3f38..15b3309538 100644 --- a/packages/commons/tests/unit/Utility.test.ts +++ b/packages/commons/tests/unit/Utility.test.ts @@ -15,6 +15,12 @@ describe('Class: Utility', () => { public validateServiceName(serviceName: string): boolean { return this.isValidServiceName(serviceName); } + public getInitializationType(): + | 'unknown' + | 'on-demand' + | 'provisioned-concurrency' { + return super.getInitializationType(); + } } it('returns the correct cold start value', () => { @@ -27,6 +33,15 @@ describe('Class: Utility', () => { expect(utility.dummyMethod()).toBe(false); }); + it('returns the correct cold start value when provisioned concurrency is used', () => { + // Prepare + process.env.AWS_LAMBDA_INITIALIZATION_TYPE = 'provisioned-concurrency'; + const utility = new TestUtility(); + + // Act & Assess + expect(utility.dummyMethod()).toBe(false); + }); + it('flips the cold start value', () => { // Prepare const utility = new TestUtility(); @@ -54,4 +69,23 @@ describe('Class: Utility', () => { expect(utility.validateServiceName('serverlessAirline')).toBe(true); expect(utility.validateServiceName('')).toBe(false); }); + + it.each([ + { value: 'on-demand', expected: 'on-demand' }, + { value: 'provisioned-concurrency', expected: 'provisioned-concurrency' }, + { value: '', expected: 'unknown' }, + ])( + 'returns the correct initialization type ($value)', + ({ value, expected }) => { + // Prepare + process.env.AWS_LAMBDA_INITIALIZATION_TYPE = value; + const utility = new TestUtility(); + + // Act + const initializationType = utility.getInitializationType(); + + // Assess + expect(initializationType).toBe(expected); + } + ); }); diff --git a/packages/commons/tests/unit/awsSdkUtils.test.ts b/packages/commons/tests/unit/awsSdkUtils.test.ts index c8f233e355..7af7af9d3a 100644 --- a/packages/commons/tests/unit/awsSdkUtils.test.ts +++ b/packages/commons/tests/unit/awsSdkUtils.test.ts @@ -6,6 +6,10 @@ import { PT_VERSION as version, } from '../../src/index.js'; +vi.hoisted(() => { + process.env.AWS_EXECUTION_ENV = ''; +}); + describe('Helpers: awsSdk', () => { describe('Function: userAgentMiddleware', () => { beforeAll(() => { diff --git a/packages/commons/vitest.config.ts b/packages/commons/vitest.config.ts index d5aa737c68..9f1196ef1f 100644 --- a/packages/commons/vitest.config.ts +++ b/packages/commons/vitest.config.ts @@ -3,5 +3,6 @@ import { defineProject } from 'vitest/config'; export default defineProject({ test: { environment: 'node', + setupFiles: ['../testing/src/setupEnv.ts'], }, }); From ee8860e54a72fdbb95281ee47eedee8872caec4d Mon Sep 17 00:00:00 2001 From: Andrea Amorosi Date: Thu, 13 Mar 2025 16:41:20 +0100 Subject: [PATCH 2/6] docs(commons): docstring --- packages/commons/src/Utility.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/commons/src/Utility.ts b/packages/commons/src/Utility.ts index d43edc0ebf..15b880a97d 100644 --- a/packages/commons/src/Utility.ts +++ b/packages/commons/src/Utility.ts @@ -63,7 +63,7 @@ export class Utility { } /** - * Get the value of the `POWERTOOLS_SERVICE_NAME` environment variable. + * Get the value of the `AWS_LAMBDA_INITIALIZATION_TYPE` environment variable. */ protected getInitializationType(): | 'unknown' From 8f64ff0353412e6d8c1b3068c24a336c56569ab1 Mon Sep 17 00:00:00 2001 From: Andrea Amorosi Date: Fri, 14 Mar 2025 18:28:15 +0100 Subject: [PATCH 3/6] test: advanced logger use case --- packages/commons/src/Utility.ts | 5 ++++- packages/logger/tests/e2e/advancedUses.test.ts | 4 ++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/commons/src/Utility.ts b/packages/commons/src/Utility.ts index 15b880a97d..89f1dbd03d 100644 --- a/packages/commons/src/Utility.ts +++ b/packages/commons/src/Utility.ts @@ -51,7 +51,10 @@ * ``` */ export class Utility { - #initializationType: 'unknown' | 'on-demand' | 'provisioned-concurrency'; + readonly #initializationType: + | 'unknown' + | 'on-demand' + | 'provisioned-concurrency'; protected coldStart = true; protected readonly defaultServiceName: string = 'service_undefined'; diff --git a/packages/logger/tests/e2e/advancedUses.test.ts b/packages/logger/tests/e2e/advancedUses.test.ts index c41aaec409..6682042226 100644 --- a/packages/logger/tests/e2e/advancedUses.test.ts +++ b/packages/logger/tests/e2e/advancedUses.test.ts @@ -12,6 +12,7 @@ import { RESOURCE_NAME_PREFIX, STACK_OUTPUT_LOG_GROUP } from './constants.js'; * In this e2e test for Logger, we test a number of advanced use cases: * - Log buffering enabled with flush on error (both manually on logger.error and automatically on uncaught error) * - Correlation ID injection (both manually and automatically) + * - Cold start detection for provisioned concurrency (always false) * * The test is split into three cases: * - Manual instrumentation @@ -127,6 +128,7 @@ describe('Logger E2E - Advanced uses', () => { expect.objectContaining({ level: 'INFO', message: 'an info log', + cold_start: false, correlation_id: correlationId, }) ); @@ -136,6 +138,7 @@ describe('Logger E2E - Advanced uses', () => { expect.objectContaining({ level: 'DEBUG', message: 'a buffered debug log', + cold_start: false, correlation_id: correlationId, }) ); @@ -145,6 +148,7 @@ describe('Logger E2E - Advanced uses', () => { expect.objectContaining({ level: 'ERROR', message: 'Uncaught error detected, flushing log buffer before exit', + cold_start: false, correlation_id: correlationId, error: expect.objectContaining({ name: 'Error', From 3b0fbfcb5650182d9f3b23ea8d3a4a6f9e51ff35 Mon Sep 17 00:00:00 2001 From: Andrea Amorosi Date: Fri, 14 Mar 2025 18:49:55 +0100 Subject: [PATCH 4/6] test: multi-region tests --- .github/workflows/run-e2e-tests.yml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/.github/workflows/run-e2e-tests.yml b/.github/workflows/run-e2e-tests.yml index 0601b33d7f..981444c78e 100644 --- a/.github/workflows/run-e2e-tests.yml +++ b/.github/workflows/run-e2e-tests.yml @@ -66,11 +66,18 @@ jobs: uses: aws-powertools/actions/.github/actions/cached-node-modules@29979bc5339bf54f76a11ac36ff67701986bb0f0 with: nodeVersion: '22' + - name: Round robin region + id: round-robin-region + run: | + regions_available=(eu-west-1 us-east-1) + region=${regions_available[$((RANDOM % ${#regions[@]}))]} + # Set the region as an output variable + echo "region=$region" >> $GITHUB_OUTPUT - name: Setup AWS credentials uses: aws-actions/configure-aws-credentials@ececac1a45f3b08a01d2dd070d28d111c5fe6722 # v4.1.0 with: role-to-assume: ${{ secrets.AWS_ROLE_ARN_TO_ASSUME }} - aws-region: eu-west-1 + aws-region: ${{ steps.round-robin-region.outputs.region }} mask-aws-account-id: true - name: Run integration tests on utils env: From ea65ce280ae62bdd5ebc1424513597b70660f72b Mon Sep 17 00:00:00 2001 From: Andrea Amorosi Date: Fri, 14 Mar 2025 18:52:31 +0100 Subject: [PATCH 5/6] test: multi-region tests --- .github/workflows/run-e2e-tests.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/run-e2e-tests.yml b/.github/workflows/run-e2e-tests.yml index 981444c78e..139e08ab17 100644 --- a/.github/workflows/run-e2e-tests.yml +++ b/.github/workflows/run-e2e-tests.yml @@ -70,9 +70,10 @@ jobs: id: round-robin-region run: | regions_available=(eu-west-1 us-east-1) - region=${regions_available[$((RANDOM % ${#regions[@]}))]} + region=${regions_available[$((RANDOM % ${#regions_available[@]}))]} # Set the region as an output variable echo "region=$region" >> $GITHUB_OUTPUT + echo "deployment_region=$region" - name: Setup AWS credentials uses: aws-actions/configure-aws-credentials@ececac1a45f3b08a01d2dd070d28d111c5fe6722 # v4.1.0 with: From 8b934e35d0a211944651a886b6e879518c75780f Mon Sep 17 00:00:00 2001 From: Andrea Amorosi Date: Mon, 17 Mar 2025 10:36:15 +0100 Subject: [PATCH 6/6] chore: revert changes to e2e workflow --- .github/workflows/run-e2e-tests.yml | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/.github/workflows/run-e2e-tests.yml b/.github/workflows/run-e2e-tests.yml index 139e08ab17..0601b33d7f 100644 --- a/.github/workflows/run-e2e-tests.yml +++ b/.github/workflows/run-e2e-tests.yml @@ -66,19 +66,11 @@ jobs: uses: aws-powertools/actions/.github/actions/cached-node-modules@29979bc5339bf54f76a11ac36ff67701986bb0f0 with: nodeVersion: '22' - - name: Round robin region - id: round-robin-region - run: | - regions_available=(eu-west-1 us-east-1) - region=${regions_available[$((RANDOM % ${#regions_available[@]}))]} - # Set the region as an output variable - echo "region=$region" >> $GITHUB_OUTPUT - echo "deployment_region=$region" - name: Setup AWS credentials uses: aws-actions/configure-aws-credentials@ececac1a45f3b08a01d2dd070d28d111c5fe6722 # v4.1.0 with: role-to-assume: ${{ secrets.AWS_ROLE_ARN_TO_ASSUME }} - aws-region: ${{ steps.round-robin-region.outputs.region }} + aws-region: eu-west-1 mask-aws-account-id: true - name: Run integration tests on utils env: