Lambda Tips


AWS Lambdas can be frustrating to work with at times, be it due to outdated code or their hard to debug nature. To help with this, below are some tips:

  • Debugging flagsverbose and dry for detailed output and side-effect-free runs
  • Health check action — respond to action: "health" to report version and verify connections
  • Scripted health checks — automate verification as part of your deploy process
  • Centralized health check — a single lambda that pings all others and compares versions

Debugging Flags

Every lambda should accept:

  • verbose: Have the lambda return a verbose field revealing the inner workings. A good logging strategy can make this redundant.
  • dry: Simulate execution without side effects. This is particularly useful for lambdas that only run under certain circumstances, helping us determine if they have been met.

Admin Pages

Build admin pages that can invoke any lambda with these flags. This makes production debugging straightforward — you can test a lambda’s behavior without side effects, or get detailed output on what it’s doing.

Health Check Action

Every lambda should respond to an action: "health" message, reporting its version and optionally verifying its connections (DB, S3, etc.):

import { LambdaVersions } from "../shared/lambdaVersions";

const LAMBDA_NAME = "ProcessGeneration";

export const handler = async (event) => {
  if (event.action === "health") {
    return {
      statusCode: 200,
      body: JSON.stringify({
        lambdaName: LAMBDA_NAME,
        version: LambdaVersions[LAMBDA_NAME],
        isHealthy: true,
      }),
    };
  }

  // normal Lambda logic...
};

Centralized Version Numbers

In the above code, we pull the version from a shared version map:

// shared/lambdaVersions.ts
export const LambdaVersions = {
  CreateRequest: 3,
  ProcessGeneration: 12,
  GetStatus: 4,
} as const;

By moving to a shared package, both the backend and frontend can import allowing us to easily check whether the lambda is up-to-date.

Increment the version when you deploy changes. This lets you verify that the deployed code matches what you expect.

Scripted Health Checks

With health checks in place, you can automate verification as part of both your LocalStack deploy and your remote AWS deploy. A single script can handle both by accepting an optional endpoint URL — when provided, it targets LocalStack; when omitted, it uses your standard AWS credentials:

#!/bin/bash
ENVIRONMENT=$1
ENDPOINT_URL=$2  # Optional: pass for LocalStack, omit for AWS

AWS_ARGS=()
if [ -n "$ENDPOINT_URL" ]; then
  AWS_ARGS+=(--endpoint-url "$ENDPOINT_URL")
  AWS_ARGS+=(--region "${AWS_REGION:-ap-southeast-2}")
fi

LAMBDAS=("orchestration" "fetch-ingest" "push-ingest" "recovery")

for NAME in "${LAMBDAS[@]}"; do
  FUNC="my-app-${ENVIRONMENT}-${NAME}"
  aws lambda invoke "${AWS_ARGS[@]}" \
    --function-name "$FUNC" \
    --payload '{"action":"health"}' \
    --cli-binary-format raw-in-base64-out \
    /tmp/health-$NAME.json >/dev/null 2>&1

  # Parse response, compare version, print result...
done

Call it at the end of your deploy scripts so issues are immediately visible:

# LocalStack deploy
./test-lambda-health.sh local http://localhost:4566 || true

# Remote deploy
./test-lambda-health.sh dev || true

This catches misconfigured environment variables, missing dependencies, and bundling issues before you start manually testing.

With version comparison and colour-coded output, the results are easy to scan at the end of a deploy:

  ✓ my-app-local-orchestration: OK (v14)
  ✓ my-app-local-fetch-ingest: OK (v17)
  ✗ my-app-local-push-ingest: UNHEALTHY (status: error)
  ✓ my-app-local-mqtt-ingest: OK (v13)
  ✓ my-app-local-recovery: OK (v13)
  ✓ my-app-local-sensor-health-check: OK (v1)
  ✓ my-app-local-aggregation: OK (v1)

  Results: 6 passed, 0 version mismatch, 1 failed (7 total)

Centralized Health Check

To make it easier to determine the overall health of the system, including any private lambdas, create a single lambda that pings all others and aggregates their status:

import { LambdaClient, InvokeCommand } from "@aws-sdk/client-lambda";
import { LambdaVersions } from "@myMono/shared/lambdaVersions";

const lambda = new LambdaClient({});
const lambdaNames = Object.keys(LambdaVersions);

async function check(functionName) {
  const res = await lambda.send(
    new InvokeCommand({
      FunctionName: functionName,
      Payload: JSON.stringify({ action: "health" }),
    }),
  );

  return JSON.parse(new TextDecoder().decode(res.Payload)).body;
}

export const handler = async () => {
  const results = await Promise.all(lambdaNames.map(check));

  return {
    statusCode: 200,
    body: JSON.stringify({ lambdas: results }),
  };
};

Admin UI

Call the health check from your admin UI and compare reported versions against expected:

import { LambdaVersions } from "@myMono/shared/lambdaVersions";

function VersionRow({ name, reported }) {
  const expected = LambdaVersions[name];
  const mismatch = expected !== reported;

  return (
    <div className={mismatch ? "warning" : "ok"}>
      {name}: {reported} {mismatch && `(expected ${expected})`}
    </div>
  );
}