This directory contains scripts for bundling, deploying, and load-testing the Deno Edge Runtime using ESZIP bundles.
bundle-eszip.sh- Bundle all examples in ESZIP formatbundle-snapshot.sh- Bundle all examples in snapshot format (with ESZIP fallback) as a smoke test ofexamples/
deploy-and-test-eszip.sh- Deploy ESZIP bundles and run k6 load testsload-test.js- k6 load testing script (JavaScript)
sign-bundle.sh- Sign an ESZIP/package bundle with Ed25519 and print base64 signature/headerdeploy-signed-bundle.sh- Sign and deploy/update a bundle in a single command (sign + curl)
run-benchmarks.sh- Full end-to-end benchmark (build, bundle, deploy, test everything)quick-benchmark.sh- Fast re-run of benchmarks without rebuildingbenchmark-context-isolate-extreme.sh- Extreme comparative benchmark (legacy vs context+isolate) with consolidated stdout reportnode-crypto-benchmark.sh- Focused benchmark/check fornode:cryptothroughput/latency (createHash,createHmac,randomBytes)zlib-guardrail-benchmark.sh- Focused benchmark/check fornode:zlibhardening guardrailsstart-observability-runtime.sh- Start observability docker stack + run edge runtime with OTEL + open Grafana
- Rust & Cargo - For building the project
- k6 - For load testing
# macOS brew install k6 # Linux / using Docker docker run -i grafana/k6 run - < load-test.js
- curl - For deployment (usually pre-installed)
- jq (optional) - For prettier JSON output of metrics
# Make scripts executable
chmod +x ./scripts/*.sh
# Run complete benchmark (build + bundle + deploy + test ESZIP)
./scripts/run-benchmarks.shThis will:
- Build the release binary
- Bundle all examples in ESZIP format
- Start the server
- Deploy and test ESZIP bundles with k6
- Display metrics and performance summary
./scripts/quick-benchmark.sh./scripts/node-crypto-benchmark.shThis runs a focused microbenchmark test and reports throughput/latency for:
createHash('sha256')createHmac('sha256')randomBytes(32)
./scripts/benchmark-context-isolate-extreme.shThis benchmark runs two scenarios and prints a final comparative report in stdout:
legacymode (no context-pool scheduler)context+isolatemode (--pool-enabled --context-pool-enabled)
Measured outputs include:
- HTTP totals and latency (
avg,p95) - deterministic status distribution (
200,503, unexpected) - routing saturation metrics (
total_contexts,total_isolates,saturated_contexts,saturated_isolates,saturated_rejections) - percentage delta between context+isolate and legacy
Main tuning knobs (via env vars):
VUS_WARMUP=50 \
VUS_STEADY=150 \
VUS_EXTREME=400 \
DUR_EXTREME=45s \
HOLD_MS=50 \
./scripts/benchmark-context-isolate-extreme.sh./scripts/start-observability-runtime.shOpen all observability UIs:
./scripts/start-observability-runtime.sh --allThis will:
- Start
observability/docker-compose.yml - Run
cargo run -- start --print-isolate-logs falsewith OTEL env vars set - Wait for readiness checks (
Grafanaand runtime/_internal/health) - Open Grafana (
http://localhost:3000) in your browser
With --all, it also opens:
- VictoriaMetrics UI (
http://localhost:8428/vmui) - Prometheus (
http://localhost:9090) - Tempo (
http://localhost:3200) - Loki (
http://localhost:3100)
You can override OTEL vars before running, for example:
EDGE_RUNTIME_OTEL_SERVICE_NAME=my-local-runtime \
EDGE_RUNTIME_OTEL_ENDPOINT=http://127.0.0.1:4318 \
./scripts/start-observability-runtime.sh# Build the project
cargo build --release
# Bundle examples
./scripts/bundle-eszip.sh./target/release/thunder start --host 0.0.0.0 --port 9000./scripts/sign-bundle.sh \
--bundle ./hello.eszip \
--private-key ./bundle-signing-private.pem \
--print-headerThis prints the x-bundle-signature-ed25519 value to include in deploy/update requests when bundle signature enforcement is enabled.
./scripts/deploy-signed-bundle.sh \
--bundle ./hello.eszip \
--function hello \
--private-key ./bundle-signing-private.pem \
--api-key admin-secretFor update flow, pass --method PUT.
In a new terminal:
# Test ESZIP format
./scripts/deploy-and-test-eszip.shThe k6 load test (load-test.js) measures:
- Cold Start: Time to initialize a new function instance
- Warm Start: Time for subsequent requests (function already loaded)
- Response Time: Total request/response time
- Throughput: Requests per second
- Error Rate: Failed requests percentage
- 10s ramp-up (1 VU) - Single user, measures cold start
- 30s ramp (1→5 VU) - Gradual increase
- 30s sustained load (10 VU) - Full load warm start measurement
- 10s ramp-down (10→0 VU) - Graceful shutdown
hello- Simple responsejson-api- JSON serializationcors- CORS headersbasic-auth- Authenticationerror-handling- Error scenariosmiddleware- Middleware chainsurl-redirect- URL redirection
The server exposes metrics at http://localhost:9000/_internal/metrics:
{
"functions": [
{
"name": "hello",
"status": "running",
"metrics": {
"total_requests": 150,
"cold_starts": 1,
"avg_cold_start_ms": 250,
"avg_warm_request_ms": 15,
"total_errors": 0
}
}
]
}- cold_starts: Number of times the function was initialized
- avg_cold_start_ms: Average time to initialize (lower is better)
- avg_warm_request_ms: Average time per request once loaded (lower is better)
- total_requests: Total requests processed
- total_errors: Number of failed requests
ESZIP (Current):
- ✅ Modules loaded from archive at runtime
- ✅ Better compatibility
⚠️ Extension initialization happens per-function- Average cold start: ~250-300ms
# Kill existing process
pkill -f "thunder.*start"# Install k6
brew install k6 # macOS
# or use Docker
docker run -i grafana/k6 run - < ./scripts/load-test.js# Check logs
tail -f /tmp/thunder.log
# Ensure no other process is using port 9000
lsof -i :9000# May need to wait for functions to initialize
sleep 5
# Check if functions were deployed
curl http://localhost:9000/_internal/functionsAfter running benchmarks:
- Bundles:
./bundles/eszip/ - Server Log:
/tmp/thunder.log - k6 Results: Displayed in console (HTML report optional with
-o html)
Edit load-test.js to change:
stages- Test duration and VU (virtual user) countEXAMPLES- List of functions to testBASE_URL- Server address
Use k6 directly to export summaries and reports:
k6 run scripts/load-test.js --summary-export=/tmp/summary.jsonEdit load-test.js:
const EXAMPLES = [
'hello',
'json-api',
// etc.
];- Increase cache locality: More warm starts = better amortized performance
- Monitor cold starts: Look for patterns in initialization time
- Profile extensions: Check which extensions take longest to initialize
- Bundle size control: Keep dependencies lean to reduce startup overhead
- Main README:
../README.md - Bundle format docs:
../crates/functions/src/types.rs - Load test configuration:
./load-test.js