In this lesson, you will learn how to leverage TypeScript decorators to instrument the execution lifecycle of serverless functions, specifically targeting cold starts and total invocation duration.
The Lifecycle Visibility Challenge
In serverless environments like AWS Lambda, the "cold start"—the time taken to initialize your runtime environment and load your dependencies—is often invisible to standard function tracing. Because the initialization code runs outside your primary handler logic, conventional spans often start after the function has already thawed.
To gain full observability, we can use class-based decorators to wrap our handler methods. By capturing a timestamp at the global scope (during the container initialization) and another inside the decorator, we can accurately measure the cold start penalty versus the execution duration.
Implementing Lifecycle Tracing
We can create a decorator that automatically records the coldStart flag and the duration of the function execution as attributes on our active trace span.
function TraceLifecycle() {
let isColdStart = true;
return function (target: any, key: string, descriptor: PropertyDescriptor) {
const originalMethod = descriptor.value;
descriptor.value = async function (...args: any[]) {
const span = tracer.startSpan('serverless.lifecycle');
span.setAttribute('faas.cold_start', isColdStart);
const start = Date.now();
try {
return await originalMethod.apply(this, args);
} finally {
span.setAttribute('faas.execution_duration', Date.now() - start);
isColdStart = false; // Subsequent invocations are warm
span.end();
}
};
};
}
In this implementation, the isColdStart variable lives in the closure of the module, persisting as long as the execution environment is reused. The first time the function is called, isColdStart is true. On subsequent warm invocations, it correctly reports false. By decorating your handler method with @TraceLifecycle(), you push the observability layer away from the business logic and into the infrastructure metadata. This allows you to distinguish between latency caused by your database queries and latency caused by the cloud provider’s initialization phase.
Key Takeaway: Using decorators to wrap serverless handlers allows you to decouple execution metrics from business logic, providing granular insight into the cold start penalty versus actual processing time.