in src/shared/sam/localLambdaRunner.ts [335:428]
export async function runLambdaFunction(
ctx: ExtContext,
config: SamLaunchRequestArgs,
onAfterBuild: () => Promise<void>
): Promise<SamLaunchRequestArgs> {
// Verify if Docker is running
const dockerResponse = await new ChildProcess('docker', ['ps'], { logging: 'no' }).run()
if (dockerResponse.exitCode !== 0 || dockerResponse.stdout.includes('error during connect')) {
throw new Error('Running AWS SAM projects locally requires Docker. Is it installed and running?')
}
// Switch over to the output channel so the user has feedback that we're getting things ready
ctx.outputChannel.show(true)
if (!config.noDebug) {
const msg =
(config.invokeTarget.target === 'api' ? `API "${config.api?.path}", ` : '') +
`Lambda "${config.handlerName}"`
getLogger('channel').info(localize('AWS.output.sam.local.startDebug', 'Preparing to debug locally: {0}', msg))
} else {
getLogger('channel').info(
localize('AWS.output.sam.local.startRun', 'Preparing to run locally: {0}', config.handlerName)
)
}
const envVars = {
...(config.awsCredentials ? asEnvironmentVariables(config.awsCredentials) : {}),
...(config.aws?.region ? { AWS_DEFAULT_REGION: config.aws.region } : {}),
}
const timer = createLambdaTimer(ctx.settings)
if (!(await buildLambdaHandler(timer, envVars, config))) {
return config
}
await onAfterBuild()
timer.refresh()
if (!(await invokeLambdaHandler(timer, envVars, config))) {
return config
}
if (!config.noDebug) {
if (config.invokeTarget.target === 'api') {
const payload =
config.eventPayloadFile === undefined
? undefined
: JSON.parse(await readFile(config.eventPayloadFile, { encoding: 'utf-8' }))
// Send the request to the local API server.
await requestLocalApi(ctx, config.api!, config.apiPort!, payload)
// Wait for cue messages ("Starting debugger" etc.) before attach.
if (!(await samStartApi)) {
return config
}
}
if (config.onWillAttachDebugger) {
getLogger('channel').info(
localize('AWS.output.sam.local.waiting', 'Waiting for SAM application to start...')
)
await config.onWillAttachDebugger(config.debugPort!, timer)
}
// HACK: remove non-serializable properties before attaching.
// TODO: revisit this :)
// eslint-disable-next-line @typescript-eslint/unbound-method
config.onWillAttachDebugger = undefined
config.samLocalInvokeCommand = undefined
await attachDebugger({
debugConfig: config,
retryDelayMillis: ATTACH_DEBUGGER_RETRY_DELAY_MILLIS,
onRecordAttachDebuggerMetric: (attachResult: boolean | undefined, attempts: number): void => {
telemetry.recordSamAttachDebugger({
lambdaPackageType: isImageLambdaConfig(config) ? 'Image' : 'Zip',
runtime: config.runtime as telemetry.Runtime,
result: attachResult ? 'Succeeded' : 'Failed',
attempts: attempts,
duration: timer.elapsedTime,
architecture: config.architecture,
})
},
})
.then(r => {
if (r.success) {
showDebugConsole()
}
})
.catch(e => {
getLogger().error(`Failed to debug: ${e}`)
globals.outputChannel.appendLine(`Failed to debug: ${e}`)
})
}
return config
}