Skip to content

Instantly share code, notes, and snippets.

@randallb
Created January 10, 2024 02:16
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save randallb/a1aa7983b0cb798ec526e3c43b54e582 to your computer and use it in GitHub Desktop.
Save randallb/a1aa7983b0cb798ec526e3c43b54e582 to your computer and use it in GitHub Desktop.
deno runtime for aws lambda
import type { Handler } from "packages/lib/types/Handler.ts";
import { shutdownBackend } from "packages/events/mod.ts";
// import { createLogger } from "packages/logs/mod.ts";
import { APIGatewayEvent } from "packages/lib/types/aws.ts";
function createLogger(..._args: Array<string>) {
return console.log;
}
const log = createLogger("lambda:runtime", "debug");
const logInfo = createLogger("lambda:runtime", "info");
const logError = createLogger("lambda:runtime", "error");
let abortController = new AbortController();
let isShuttingDown = false;
async function handleShutdown() {
if (isShuttingDown) return;
isShuttingDown = true;
logInfo("Shutting down gracefully...");
// Abort the ongoing fetch operation
abortController.signal.onabort = async () => {
logInfo("killed request");
await Deno.writeTextFile(
"/tmp/.restart",
`${Date.now()}`,
);
};
abortController.abort();
}
globalThis.addEventListener("unload", handleShutdown);
const AWS_LAMBDA_RUNTIME_API = Deno.env.get(
"AWS_LAMBDA_RUNTIME_API",
);
async function respond<T>(
lambdaRuntimeIncomingRequest: Response,
handler: Handler<T>,
) {
const requestId = lambdaRuntimeIncomingRequest.headers.get(
"Lambda-Runtime-Aws-Request-Id",
);
if (!requestId) throw new Error("Missing Lambda-Runtime-Aws-Request-Id");
log("debug", "Processing request", requestId);
let responseBody = {
statusCode: 500,
body: "My bad!",
};
try {
const awsRequest = await lambdaRuntimeIncomingRequest.json();
responseBody = await handler(awsRequest);
} catch (error) {
logError("error", error);
throw error;
}
const awsResponse = await fetch(
`http://${AWS_LAMBDA_RUNTIME_API}/2018-06-01/runtime/invocation/${requestId}/response`,
{
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(responseBody),
},
);
await shutdownBackend();
return awsResponse;
}
export default async function serveLambda<T = APIGatewayEvent>(
handler: Handler<T>,
) {
const args = Deno.args;
if (args[0] === "cache") {
log("Exiting because all we wanted to do was cache the dependencies");
return;
}
log("info", "Starting Lambda runtime server");
logInfo(`waiting at ${Date.now()}`);
while (true) {
log("debug", "Awaiting request");
try {
const incomingRequest = await fetch(
`http://${AWS_LAMBDA_RUNTIME_API}/2018-06-01/runtime/invocation/next`,
{
signal: abortController.signal,
},
);
await respond<T>(incomingRequest, handler);
} catch (_e) {
break;
}
abortController = new AbortController();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment