Skip to content

Commit f171b1c

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.
1 parent 66f7471 commit f171b1c

File tree

4 files changed

+51
-6
lines changed

4 files changed

+51
-6
lines changed

src/trace/listener.ts

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,12 @@ 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 {
9+
didFunctionColdStart,
10+
isProactiveInitialization,
11+
isManagedInstancesMode,
12+
isProvisionedConcurrency,
13+
} from "../utils/cold-start";
914
import { datadogLambdaVersion } from "../constants";
1015
import { ddtraceVersion, parentSpanFinishTimeHeader, DD_SERVICE_ENV_VAR } from "./constants";
1116
import { patchConsole } from "./patch-console";
@@ -182,11 +187,10 @@ export class TraceListener {
182187
}
183188
const coldStartNodes = getTraceTree();
184189
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()) {
190+
// Skip creating cold start spans in managed instances mode or provisioned concurrency
191+
// since the gap between the sandbox init and the function invocation might be very
192+
// large (minutes or hours), making the spans misleading and not useful
193+
if (!isManagedInstancesMode() && !isProvisionedConcurrency()) {
190194
const coldStartConfig: ColdStartTracerConfig = {
191195
tracerWrapper: this.tracerWrapper,
192196
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)