Skip to content

Commit ea48ac0

Browse files
fix: skip cold start spans for provisioned concurrency
With provisioned concurrency, containers are pre-warmed before invocations, causing module load timestamps to be captured minutes (or hours) before the first invocation. This inflates aws.lambda.load span durations to the full pre-warm gap rather than the actual load time. Skip cold start span creation for provisioned-concurrency, consistent with the existing fix for lambda-managed-instances (PR #717). Fixes #723. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 66f7471 commit ea48ac0

4 files changed

Lines changed: 46 additions & 6 deletions

File tree

‎src/trace/listener.ts‎

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { patchHttp, unpatchHttp } from "./patch-http";
55
import { extractTriggerTags, extractHTTPStatusCodeTag, parseEventSource } from "./trigger";
66
import { ColdStartTracerConfig, ColdStartTracer } from "./cold-start-tracer";
77
import { logDebug, tagObject } from "../utils";
8-
import { didFunctionColdStart, isProactiveInitialization, isManagedInstancesMode } from "../utils/cold-start";
8+
import { didFunctionColdStart, isProactiveInitialization, isManagedInstancesMode, isProvisionedConcurrency } from "../utils/cold-start";
99
import { datadogLambdaVersion } from "../constants";
1010
import { ddtraceVersion, parentSpanFinishTimeHeader, DD_SERVICE_ENV_VAR } from "./constants";
1111
import { patchConsole } from "./patch-console";
@@ -182,11 +182,10 @@ export class TraceListener {
182182
}
183183
const coldStartNodes = getTraceTree();
184184
if (coldStartNodes.length > 0) {
185-
// Skip creating cold start spans in managed instances mode
186-
// since the gap between the sandbox init and the function
187-
// invocation might be too large to provide a useful trace and
188-
// experience
189-
if (!isManagedInstancesMode()) {
185+
// Skip creating cold start spans in managed instances mode or provisioned concurrency
186+
// since the gap between the sandbox init and the function invocation might be very
187+
// large (minutes or hours), making the spans misleading and not useful
188+
if (!isManagedInstancesMode() && !isProvisionedConcurrency()) {
190189
const coldStartConfig: ColdStartTracerConfig = {
191190
tracerWrapper: this.tracerWrapper,
192191
parentSpan:

‎src/utils/cold-start.spec.ts‎

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import {
44
setSandboxInit,
55
isProactiveInitialization,
66
isManagedInstancesMode,
7+
isProvisionedConcurrency,
78
} from "./cold-start";
89

910
beforeEach(_resetColdStart);
@@ -78,4 +79,31 @@ describe("cold-start", () => {
7879

7980
process.env.AWS_LAMBDA_INITIALIZATION_TYPE = originalValue;
8081
});
82+
83+
it("identifies provisioned concurrency when AWS_LAMBDA_INITIALIZATION_TYPE is set", () => {
84+
const originalValue = process.env.AWS_LAMBDA_INITIALIZATION_TYPE;
85+
86+
process.env.AWS_LAMBDA_INITIALIZATION_TYPE = "provisioned-concurrency";
87+
expect(isProvisionedConcurrency()).toEqual(true);
88+
89+
process.env.AWS_LAMBDA_INITIALIZATION_TYPE = originalValue;
90+
});
91+
92+
it("identifies non-provisioned concurrency when AWS_LAMBDA_INITIALIZATION_TYPE is not set", () => {
93+
const originalValue = process.env.AWS_LAMBDA_INITIALIZATION_TYPE;
94+
95+
delete process.env.AWS_LAMBDA_INITIALIZATION_TYPE;
96+
expect(isProvisionedConcurrency()).toEqual(false);
97+
98+
process.env.AWS_LAMBDA_INITIALIZATION_TYPE = originalValue;
99+
});
100+
101+
it("identifies non-provisioned concurrency when AWS_LAMBDA_INITIALIZATION_TYPE has different value", () => {
102+
const originalValue = process.env.AWS_LAMBDA_INITIALIZATION_TYPE;
103+
104+
process.env.AWS_LAMBDA_INITIALIZATION_TYPE = "on-demand";
105+
expect(isProvisionedConcurrency()).toEqual(false);
106+
107+
process.env.AWS_LAMBDA_INITIALIZATION_TYPE = originalValue;
108+
});
81109
});

‎src/utils/cold-start.ts‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,18 @@ export function isManagedInstancesMode(): boolean {
4747
return process.env.AWS_LAMBDA_INITIALIZATION_TYPE === "lambda-managed-instances";
4848
}
4949

50+
/**
51+
* Checks if the Lambda function is running with provisioned concurrency.
52+
* With provisioned concurrency, containers are pre-warmed before invocations,
53+
* so the gap between initialization and invocation can be very large (minutes or hours).
54+
* Cold start spans created from pre-warm module load times would have inflated durations
55+
* and are not useful in the context of the actual invocation.
56+
* @returns true if running with provisioned concurrency, false otherwise
57+
*/
58+
export function isProvisionedConcurrency(): boolean {
59+
return process.env.AWS_LAMBDA_INITIALIZATION_TYPE === "provisioned-concurrency";
60+
}
61+
5062
// For testing, reset the globals to their original values
5163
export function _resetColdStart() {
5264
functionDidColdStart = true;

‎src/utils/index.ts‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ export {
44
setSandboxInit,
55
isProactiveInitialization,
66
isManagedInstancesMode,
7+
isProvisionedConcurrency,
78
} from "./cold-start";
89
export { promisifiedHandler } from "./handler";
910
export { Timer } from "./timer";

0 commit comments

Comments
 (0)