Skip to content

Commit

Permalink
feat(runtime,serverless): add V8 heap snapshots (#591)
Browse files Browse the repository at this point in the history
* feat(runtime): use v8 snapshot for runtime code

* feat: run all tests with and without snapshot

* chore: add changesets

* fix(serverless): add back thread isolate

* feat: build serverless before running runtime tests
  • Loading branch information
QuiiBz authored Feb 17, 2023
1 parent fda836c commit 0b422d6
Show file tree
Hide file tree
Showing 30 changed files with 842 additions and 447 deletions.
6 changes: 6 additions & 0 deletions .changeset/early-wombats-ring.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@lagon/runtime': patch
'@lagon/js-runtime': patch
---

Split sync and async bindings into LagonSync/LagonAsync
6 changes: 6 additions & 0 deletions .changeset/healthy-rice-fly.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@lagon/runtime': patch
'@lagon/serverless': patch
---

Add option to load V8 heap snapshot
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,4 @@ storybook-static/
.DS_Store
.env
tsconfig.tsbuildinfo
snapshot.bin
4 changes: 4 additions & 0 deletions crates/runtime/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,7 @@ lagon-runtime-http = { path = "../runtime_http" }
lagon-runtime-isolate = { path = "../runtime_isolate" }
log = { version = "0.4.17", features = ["std", "kv_unstable", "kv_unstable_serde"] }
serial_test = "1.0.0"

[features]
default = []
ignore-snapshot = ["lagon-runtime-isolate/ignore-snapshot"]
2 changes: 1 addition & 1 deletion crates/runtime/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"private": true,
"scripts": {
"build": "cargo build",
"test": "cargo test",
"test": "cargo test && cargo test --features ignore-snapshot",
"lint": "cargo clippy -- -Dwarnings --no-deps"
}
}
123 changes: 78 additions & 45 deletions crates/runtime/tests/crypto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,17 @@ fn setup() {
#[tokio::test]
async fn crypto_random_uuid() {
setup();
let mut isolate = Isolate::new(IsolateOptions::new(
"export function handler() {
let mut isolate = Isolate::new(
IsolateOptions::new(
"export function handler() {
const uuid = crypto.randomUUID();
const secondUuid = crypto.randomUUID();
return new Response(`${typeof uuid} ${uuid.length} ${uuid === secondUuid}`);
}"
.into(),
));
.into(),
)
.snapshot_blob(include_bytes!("../../serverless/snapshot.bin")),
);
let (tx, rx) = flume::unbounded();
isolate.run(Request::default(), tx).await;

Expand All @@ -34,14 +37,17 @@ async fn crypto_random_uuid() {
#[tokio::test]
async fn crypto_get_random_values() {
setup();
let mut isolate = Isolate::new(IsolateOptions::new(
"export function handler() {
let mut isolate = Isolate::new(
IsolateOptions::new(
"export function handler() {
const typedArray = new Uint8Array([0, 8, 2]);
const result = crypto.getRandomValues(typedArray);
return new Response(`${result == typedArray} ${typedArray.length} ${result.length}`);
}"
.into(),
));
.into(),
)
.snapshot_blob(include_bytes!("../../serverless/snapshot.bin")),
);
let (tx, rx) = flume::unbounded();
isolate.run(Request::default(), tx).await;

Expand All @@ -54,13 +60,16 @@ async fn crypto_get_random_values() {
#[tokio::test]
async fn crypto_get_random_values_throw_not_typedarray() {
setup();
let mut isolate = Isolate::new(IsolateOptions::new(
"export function handler() {
let mut isolate = Isolate::new(
IsolateOptions::new(
"export function handler() {
const result = crypto.getRandomValues(true);
return new Response(`${result == typedArray} ${typedArray.length} ${result.length}`);
}"
.into(),
));
.into(),
)
.snapshot_blob(include_bytes!("../../serverless/snapshot.bin")),
);
let (tx, rx) = flume::unbounded();
isolate.run(Request::default(), tx).await;

Expand All @@ -76,8 +85,9 @@ async fn crypto_get_random_values_throw_not_typedarray() {
#[tokio::test]
async fn crypto_key_value() {
setup();
let mut isolate = Isolate::new(IsolateOptions::new(
"export async function handler() {
let mut isolate = Isolate::new(
IsolateOptions::new(
"export async function handler() {
const { keyValue } = await crypto.subtle.importKey(
'raw',
new TextEncoder().encode('secret'),
Expand All @@ -88,8 +98,10 @@ async fn crypto_key_value() {
return new Response(`${typeof keyValue} ${keyValue.length}`);
}"
.into(),
));
.into(),
)
.snapshot_blob(include_bytes!("../../serverless/snapshot.bin")),
);
let (tx, rx) = flume::unbounded();
isolate.run(Request::default(), tx).await;

Expand All @@ -102,8 +114,9 @@ async fn crypto_key_value() {
#[tokio::test]
async fn crypto_unique_key_value() {
setup();
let mut isolate = Isolate::new(IsolateOptions::new(
"export async function handler() {
let mut isolate = Isolate::new(
IsolateOptions::new(
"export async function handler() {
const { keyValue: first } = await crypto.subtle.importKey(
'raw',
new TextEncoder().encode('secret'),
Expand All @@ -121,8 +134,10 @@ async fn crypto_unique_key_value() {
return new Response(first == second);
}"
.into(),
));
.into(),
)
.snapshot_blob(include_bytes!("../../serverless/snapshot.bin")),
);
let (tx, rx) = flume::unbounded();
isolate.run(Request::default(), tx).await;

Expand All @@ -135,8 +150,9 @@ async fn crypto_unique_key_value() {
#[tokio::test]
async fn crypto_sign() {
setup();
let mut isolate = Isolate::new(IsolateOptions::new(
"export async function handler() {
let mut isolate = Isolate::new(
IsolateOptions::new(
"export async function handler() {
const key = await crypto.subtle.importKey(
'raw',
new TextEncoder().encode('secret'),
Expand All @@ -151,8 +167,10 @@ async fn crypto_sign() {
return new Response(`${signed instanceof Uint8Array} ${signed.length}`);
}"
.into(),
));
.into(),
)
.snapshot_blob(include_bytes!("../../serverless/snapshot.bin")),
);
let (tx, rx) = flume::unbounded();
isolate.run(Request::default(), tx).await;

Expand All @@ -165,8 +183,9 @@ async fn crypto_sign() {
#[tokio::test]
async fn crypto_verify() {
setup();
let mut isolate = Isolate::new(IsolateOptions::new(
"export async function handler() {
let mut isolate = Isolate::new(
IsolateOptions::new(
"export async function handler() {
const key = await crypto.subtle.importKey(
'raw',
new TextEncoder().encode('secret'),
Expand All @@ -185,8 +204,10 @@ async fn crypto_verify() {
return new Response(verified);
}"
.into(),
));
.into(),
)
.snapshot_blob(include_bytes!("../../serverless/snapshot.bin")),
);
let (tx, rx) = flume::unbounded();
isolate.run(Request::default(), tx).await;

Expand All @@ -199,14 +220,17 @@ async fn crypto_verify() {
#[tokio::test]
async fn crypto_digest_sha1() {
setup();
let mut isolate = Isolate::new(IsolateOptions::new(
"export async function handler() {
let mut isolate = Isolate::new(
IsolateOptions::new(
"export async function handler() {
const digest = await crypto.subtle.digest('SHA-1', new TextEncoder().encode('hello, world'));
return new Response(`${digest.length} ${digest}`);
}"
.into(),
));
.into(),
)
.snapshot_blob(include_bytes!("../../serverless/snapshot.bin")),
);
let (tx, rx) = flume::unbounded();
isolate.run(Request::default(), tx).await;

Expand All @@ -221,14 +245,17 @@ async fn crypto_digest_sha1() {
#[tokio::test]
async fn crypto_digest_string() {
setup();
let mut isolate = Isolate::new(IsolateOptions::new(
"export async function handler() {
let mut isolate = Isolate::new(
IsolateOptions::new(
"export async function handler() {
const digest = await crypto.subtle.digest('SHA-256', new TextEncoder().encode('hello, world'));
return new Response(`${digest.length} ${digest}`);
}"
.into(),
));
.into(),
)
.snapshot_blob(include_bytes!("../../serverless/snapshot.bin")),
);
let (tx, rx) = flume::unbounded();
isolate.run(Request::default(), tx).await;

Expand All @@ -248,7 +275,7 @@ async fn crypto_digest_object() {
return new Response(`${digest.length} ${digest}`);
}"
.into(),
));
).snapshot_blob(include_bytes!("../../serverless/snapshot.bin")));
let (tx, rx) = flume::unbounded();
isolate.run(Request::default(), tx).await;

Expand All @@ -261,8 +288,9 @@ async fn crypto_digest_object() {
#[tokio::test]
async fn crypto_encrypt() {
setup();
let mut isolate = Isolate::new(IsolateOptions::new(
"export async function handler() {
let mut isolate = Isolate::new(
IsolateOptions::new(
"export async function handler() {
const key = await crypto.subtle.importKey(
'raw',
new TextEncoder().encode('secret'),
Expand All @@ -280,8 +308,10 @@ async fn crypto_encrypt() {
return new Response(`${ciphertext instanceof Uint8Array} ${ciphertext.length}`);
}"
.into(),
));
.into(),
)
.snapshot_blob(include_bytes!("../../serverless/snapshot.bin")),
);
let (tx, rx) = flume::unbounded();
isolate.run(Request::default(), tx).await;

Expand All @@ -294,8 +324,9 @@ async fn crypto_encrypt() {
#[tokio::test]
async fn crypto_decrypt() {
setup();
let mut isolate = Isolate::new(IsolateOptions::new(
"export async function handler() {
let mut isolate = Isolate::new(
IsolateOptions::new(
"export async function handler() {
const key = await crypto.subtle.importKey(
'raw',
new TextEncoder().encode('secret'),
Expand All @@ -319,8 +350,10 @@ async fn crypto_decrypt() {
return new Response(text);
}"
.into(),
));
.into(),
)
.snapshot_blob(include_bytes!("../../serverless/snapshot.bin")),
);
let (tx, rx) = flume::unbounded();
isolate.run(Request::default(), tx).await;

Expand Down
22 changes: 14 additions & 8 deletions crates/runtime/tests/disallow_codegen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,16 @@ fn setup() {
#[tokio::test]
async fn disallow_eval() {
setup();
let mut isolate = Isolate::new(IsolateOptions::new(
"export function handler() {
let mut isolate = Isolate::new(
IsolateOptions::new(
"export function handler() {
const result = eval('1 + 1')
return new Response(result)
}"
.into(),
));
.into(),
)
.snapshot_blob(include_bytes!("../../serverless/snapshot.bin")),
);
let (tx, rx) = flume::unbounded();
isolate.run(Request::default(), tx).await;

Expand All @@ -35,13 +38,16 @@ async fn disallow_eval() {
#[tokio::test]
async fn disallow_function() {
setup();
let mut isolate = Isolate::new(IsolateOptions::new(
"export function handler() {
let mut isolate = Isolate::new(
IsolateOptions::new(
"export function handler() {
const result = new Function('return 1 + 1')
return new Response(result())
}"
.into(),
));
.into(),
)
.snapshot_blob(include_bytes!("../../serverless/snapshot.bin")),
);
let (tx, rx) = flume::unbounded();
isolate.run(Request::default(), tx).await;

Expand Down
Loading

4 comments on commit 0b422d6

@vercel
Copy link

@vercel vercel bot commented on 0b422d6 Feb 17, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

www – ./www

www-git-main-lagon.vercel.app
lagon.dev
www-lagon.vercel.app
lagon.app

@vercel
Copy link

@vercel vercel bot commented on 0b422d6 Feb 17, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

docs – ./packages/docs

docs-lagon.vercel.app
lagon-docs.vercel.app
docs-git-main-lagon.vercel.app
docs.lagon.app

@vercel
Copy link

@vercel vercel bot commented on 0b422d6 Feb 17, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

storybook – ./packages/ui

storybook-git-main-lagon.vercel.app
storybook-lagon.vercel.app
storybook-swart-eight.vercel.app
ui.lagon.app

@vercel
Copy link

@vercel vercel bot commented on 0b422d6 Feb 17, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

dashboard – ./packages/dashboard

dashboard-lagon.vercel.app
dashboard-git-main-lagon.vercel.app
dash.lagon.app

Please sign in to comment.