Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[DNM] feat: add llrt runtime #3670

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 0 additions & 1 deletion packages/astro-sst/package.json
Expand Up @@ -50,7 +50,6 @@
"build": "tsc"
},
"dependencies": {
"@astrojs/webapi": "^3.0.0",
"set-cookie-parser": "^2.6.0"
},
"devDependencies": {
Expand Down
5 changes: 0 additions & 5 deletions packages/astro-sst/src/entrypoint.ts
Expand Up @@ -6,17 +6,12 @@ import type {
} from "aws-lambda";
import type { RequestHandler, ResponseMode, ResponseStream } from "./lib/types";
import { NodeApp } from "astro/app/node";
import { polyfill } from "@astrojs/webapi";
import { InternalEvent, convertFrom, convertTo } from "./lib/event-mapper.js";
import { debug } from "./lib/logger.js";
import { RenderOptions } from "astro/app";

const astroMajorVersion = parseInt(ASTRO_VERSION.split(".")[0] ?? 0);

polyfill(globalThis, {
exclude: "window document",
});

declare global {
const awslambda: {
streamifyResponse(handler: RequestHandler): RequestHandler;
Expand Down
1 change: 1 addition & 0 deletions packages/sst/build.mjs
Expand Up @@ -164,6 +164,7 @@ await Promise.all(
"dotnet6-bootstrap",
"nixpacks",
"service-dev-function",
"llrt-layers",
].map((dir) =>
fs.cpSync(`support/${dir}`, `dist/support/${dir}`, {
recursive: true,
Expand Down
13 changes: 12 additions & 1 deletion packages/sst/src/constructs/Function.ts
Expand Up @@ -85,6 +85,8 @@ const supportedRuntimes = {
java21: CDKRuntime.JAVA_21,
"go1.x": CDKRuntime.PROVIDED_AL2,
go: CDKRuntime.PROVIDED_AL2,
"provider.AL2023": CDKRuntime.PROVIDED_AL2023,
"llrt.experimental": CDKRuntime.PROVIDED_AL2023,
};

export type Runtime = keyof typeof supportedRuntimes;
Expand Down Expand Up @@ -1082,6 +1084,15 @@ export class Function extends CDKFunction implements SSTConstruct {
props.java?.experimentalUseProvidedRuntime
) {
cfnFunction.runtime = props.java?.experimentalUseProvidedRuntime;
} else if (props.runtime?.startsWith("llrt")) {
cfnFunction.runtime = CDKRuntime.PROVIDED_AL2023.toString();
const isArm64 = architecture === Architecture.ARM_64;
const llrtLayer = new LayerVersion(this, "llrt", {
code: Code.fromAsset(path.resolve(__dirname, `../../support/llrt-layers/llrt-lambda-${isArm64 ? "arm64" : "x86"}.zip`)),
compatibleRuntimes: [CDKRuntime.PROVIDED_AL2023],
compatibleArchitectures: [architecture],
})
props.layers?.unshift(llrtLayer)
}
});
}
Expand Down Expand Up @@ -1304,7 +1315,7 @@ export class Function extends CDKFunction implements SSTConstruct {

private isNodeRuntime() {
const { runtime } = this.props;
return runtime!.startsWith("nodejs");
return runtime!.startsWith("nodejs") || runtime!.startsWith("llrt");
}

static validateHandlerSet(id: string, props: FunctionProps) {
Expand Down
32 changes: 24 additions & 8 deletions packages/sst/src/constructs/SsrFunction.ts
Expand Up @@ -22,6 +22,7 @@ import {
FunctionOptions,
Function as CdkFunction,
FunctionUrlOptions,
LayerVersion,
} from "aws-cdk-lib/aws-lambda";
import { Bucket } from "aws-cdk-lib/aws-s3";
import {
Expand Down Expand Up @@ -58,7 +59,7 @@ export interface SsrFunctionProps
extends Omit<FunctionOptions, "memorySize" | "timeout" | "runtime"> {
bundle?: string;
handler: string;
runtime?: "nodejs16.x" | "nodejs18.x" | "nodejs20.x";
runtime?: "nodejs16.x" | "nodejs18.x" | "nodejs20.x" | "llrt.experimental";
timeout?: number | Duration;
memorySize?: number | Size;
permissions?: Permissions;
Expand Down Expand Up @@ -182,20 +183,23 @@ export class SsrFunction extends Construct implements SSTConstruct {
logRetention,
} = this.props;

return new CdkFunction(this, `ServerFunction`, {
const isLlrt = runtime?.startsWith("llrt");

const createdFunction = new CdkFunction(this, `ServerFunction`, {
...this.props,
handler: handler.split(path.sep).join(path.posix.sep),
logRetention: logRetention ?? RetentionDays.THREE_DAYS,
code: Code.fromBucket(
Bucket.fromBucketName(this, "IServerFunctionBucket", assetBucket),
assetKey
),
runtime:
runtime === "nodejs20.x"
? Runtime.NODEJS_20_X
: runtime === "nodejs16.x"
? Runtime.NODEJS_16_X
: Runtime.NODEJS_18_X,
runtime: isLlrt
? Runtime.PROVIDED_AL2023
: runtime === "nodejs20.x"
? Runtime.NODEJS_20_X
: runtime === "nodejs16.x"
? Runtime.NODEJS_16_X
: Runtime.NODEJS_18_X,
architecture,
memorySize:
typeof memorySize === "string"
Expand All @@ -207,6 +211,18 @@ export class SsrFunction extends Construct implements SSTConstruct {
: CdkDuration.seconds(timeout),
logRetentionRetryOptions: logRetention && { maxRetries: 100 },
});

if (isLlrt) {
const isArm64 = architecture === Architecture.ARM_64;
const llrtLayer = new LayerVersion(this, "llrt", {
code: Code.fromAsset(path.resolve(__dirname, `../../support/llrt-layers/llrt-lambda-${isArm64 ? "arm64" : "x86"}.zip`)),
compatibleRuntimes: [Runtime.PROVIDED_AL2023],
compatibleArchitectures: [isArm64 ? Architecture.ARM_64 : Architecture.X86_64],
})
createdFunction.addLayers(llrtLayer);
}

return createdFunction;
}

private createCodeReplacer(assetBucket: string, assetKey: string) {
Expand Down
8 changes: 6 additions & 2 deletions packages/sst/src/constructs/SsrSite.ts
Expand Up @@ -213,7 +213,7 @@ export interface SsrSiteProps {
* runtime: "nodejs20.x",
* ```
*/
runtime?: "nodejs16.x" | "nodejs18.x" | "nodejs20.x";
runtime?: "nodejs16.x" | "nodejs18.x" | "nodejs20.x" | "llrt.experimental";
/**
* Used to configure nodejs function properties
*/
Expand Down Expand Up @@ -951,10 +951,14 @@ function handler(event) {
function createEdgeFunctions() {
const functions: Record<string, EdgeFunction> = {};

if (runtime === "llrt.experimental" && Object.keys(plan.edgeFunctions ?? {}).length > 0) {
throw new Error("Edge functions are not supported with the `llrt.experimental` runtime.");
}

Object.entries(plan.edgeFunctions ?? {}).forEach(
([name, { constructId, function: props }]) => {
const fn = new EdgeFunction(self, constructId, {
runtime,
runtime: runtime as EdgeFunctionProps["runtime"],
timeout,
memorySize,
bind,
Expand Down
11 changes: 7 additions & 4 deletions packages/sst/src/runtime/handlers/node.ts
Expand Up @@ -12,7 +12,6 @@ import { useRuntimeWorkers } from "../workers.js";
import { Colors } from "../../cli/colors.js";
import { Logger } from "../../logger.js";
import { findAbove, findBelow } from "../../util/fs.js";
import { lazy } from "../../util/lazy.js";

export const useNodeHandler = (): RuntimeHandler => {
const rebuildCache: Record<
Expand Down Expand Up @@ -40,7 +39,8 @@ export const useNodeHandler = (): RuntimeHandler => {
.join(path.posix.sep);
return Boolean(cache.result.metafile?.inputs[relative]);
},
canHandle: (input) => input.startsWith("nodejs"),
canHandle: (input) =>
input.startsWith("nodejs") || input.startsWith("llrt"),
startWorker: async (input) => {
const workers = await useRuntimeWorkers();
new Promise(async () => {
Expand Down Expand Up @@ -98,6 +98,7 @@ export const useNodeHandler = (): RuntimeHandler => {

const nodejs = input.props.nodejs || {};
const isESM = (nodejs.format || "esm") === "esm";
const isLlrt = input.props.runtime?.startsWith("llrt");

const relative = path.relative(
project.paths.root,
Expand Down Expand Up @@ -144,12 +145,12 @@ export const useNodeHandler = (): RuntimeHandler => {
"sharp",
"pg-native",
...(isESM || input.props.runtime !== "nodejs16.x" ? [] : ["aws-sdk"]),
...(isLlrt ? ["aws-sdk", "@smithy", "@uuid"] : []),
];
const { external, ...override } = nodejs.esbuild || {};
if (!ctx) {
const options: BuildOptions = {
entryPoints: [file],
platform: "node",
external: [
...forceExternal,
...(nodejs.install || []),
Expand All @@ -165,7 +166,8 @@ export const useNodeHandler = (): RuntimeHandler => {
...(isESM
? {
format: "esm",
target: "esnext",
target: isLlrt ? "es2020" : "esnext",
platform: isLlrt ? "browser" : "node",
mainFields: ["module", "main"],
banner: {
js: [
Expand All @@ -180,6 +182,7 @@ export const useNodeHandler = (): RuntimeHandler => {
: {
format: "cjs",
target: "node14",
platform: "node",
banner: nodejs.banner
? {
js: nodejs.banner,
Expand Down
Binary file not shown.
Binary file not shown.