From ecb4029f1b195f0af4c6f4142b4bba2f2e457baa Mon Sep 17 00:00:00 2001 From: Harold Hunt Date: Sat, 15 Mar 2025 14:15:18 -0400 Subject: [PATCH 1/3] Export URLs on PRs --- .github/workflows/{build.yaml => build.yml} | 75 +++++++++++++++++++ .../{pr-closed.yaml => pr-closed.yml} | 0 2 files changed, 75 insertions(+) rename .github/workflows/{build.yaml => build.yml} (89%) rename .github/workflows/{pr-closed.yaml => pr-closed.yml} (100%) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yml similarity index 89% rename from .github/workflows/build.yaml rename to .github/workflows/build.yml index a9d87344..bb1a11c4 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yml @@ -722,3 +722,78 @@ jobs: for i in {1..5}; do curl ${BASE_URL}/ping done + + create-status-checks: + needs: [deploy, smoke-test] + runs-on: ubuntu-latest + if: ${{ always() && needs.deploy.result != 'failed' && github.event_name == 'pull_request' }} + steps: + - name: Create Status Checks with URLs + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + PR_NUMBER: ${{ github.event.pull_request.number }} + run: | + # Generate the URLs based on PR number + ALB_ROUTER_URL="https://lambdadispatch-pr-${PR_NUMBER}.ghpublic.pwrdrvr.com" + ALB_DEMOAPP_URL="https://lambdadispatch-demoapp-pr-${PR_NUMBER}.ghpublic.pwrdrvr.com" + NLB_ROUTER_URL="https://lambdadispatch-nlb-pr-${PR_NUMBER}.ghpublic.pwrdrvr.com" + NLB_DEMOAPP_URL="https://lambdadispatch-nlb-demoapp-pr-${PR_NUMBER}.ghpublic.pwrdrvr.com" + + # Create deployment statuses for each URL + # ALB Router + gh api repos/${{ github.repository }}/deployments \ + -F ref=${{ github.event.pull_request.head.ref }} \ + -F environment="ALB Router" \ + -F auto_merge=false \ + -F required_contexts=[] | jq .id > deployment_id_alb_router.txt + + ALB_ROUTER_ID=$(cat deployment_id_alb_router.txt) + gh api repos/${{ github.repository }}/deployments/$ALB_ROUTER_ID/statuses \ + -F state=success \ + -F environment_url=$ALB_ROUTER_URL \ + -F description="ALB Router URL" \ + -F log_url=$ALB_ROUTER_URL + + # ALB Demo App + gh api repos/${{ github.repository }}/deployments \ + -F ref=${{ github.event.pull_request.head.ref }} \ + -F environment="ALB Demo App" \ + -F auto_merge=false \ + -F required_contexts=[] | jq .id > deployment_id_alb_demoapp.txt + + ALB_DEMOAPP_ID=$(cat deployment_id_alb_demoapp.txt) + gh api repos/${{ github.repository }}/deployments/$ALB_DEMOAPP_ID/statuses \ + -F state=success \ + -F environment_url=$ALB_DEMOAPP_URL \ + -F description="ALB Demo App URL" \ + -F log_url=$ALB_DEMOAPP_URL + + # NLB Router + gh api repos/${{ github.repository }}/deployments \ + -F ref=${{ github.event.pull_request.head.ref }} \ + -F environment="NLB Router" \ + -F auto_merge=false \ + -F required_contexts=[] | jq .id > deployment_id_nlb_router.txt + + NLB_ROUTER_ID=$(cat deployment_id_nlb_router.txt) + gh api repos/${{ github.repository }}/deployments/$NLB_ROUTER_ID/statuses \ + -F state=success \ + -F environment_url=$NLB_ROUTER_URL \ + -F description="NLB Router URL (Port ${PR_NUMBER})" \ + -F log_url=$NLB_ROUTER_URL + + # NLB Demo App + gh api repos/${{ github.repository }}/deployments \ + -F ref=${{ github.event.pull_request.head.ref }} \ + -F environment="NLB Demo App" \ + -F auto_merge=false \ + -F required_contexts=[] | jq .id > deployment_id_nlb_demoapp.txt + + NLB_DEMOAPP_ID=$(cat deployment_id_nlb_demoapp.txt) + gh api repos/${{ github.repository }}/deployments/$NLB_DEMOAPP_ID/statuses \ + -F state=success \ + -F environment_url=$NLB_DEMOAPP_URL \ + -F description="NLB Demo App URL (Port ${PR_NUMBER}+10000)" \ + -F log_url=$NLB_DEMOAPP_URL + + echo "Created deployment status checks with URLs for all endpoints" diff --git a/.github/workflows/pr-closed.yaml b/.github/workflows/pr-closed.yml similarity index 100% rename from .github/workflows/pr-closed.yaml rename to .github/workflows/pr-closed.yml From 180d17e199771383635175dc9616154178c59bf9 Mon Sep 17 00:00:00 2001 From: Harold Hunt Date: Sat, 15 Mar 2025 14:57:24 -0400 Subject: [PATCH 2/3] Use a comment --- .github/workflows/build.yml | 107 ++++++++++++++---------------------- 1 file changed, 41 insertions(+), 66 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index bb1a11c4..2e04a09a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -728,72 +728,47 @@ jobs: runs-on: ubuntu-latest if: ${{ always() && needs.deploy.result != 'failed' && github.event_name == 'pull_request' }} steps: - - name: Create Status Checks with URLs + - name: Generate URLs + id: generate-urls env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} PR_NUMBER: ${{ github.event.pull_request.number }} run: | - # Generate the URLs based on PR number - ALB_ROUTER_URL="https://lambdadispatch-pr-${PR_NUMBER}.ghpublic.pwrdrvr.com" - ALB_DEMOAPP_URL="https://lambdadispatch-demoapp-pr-${PR_NUMBER}.ghpublic.pwrdrvr.com" - NLB_ROUTER_URL="https://lambdadispatch-nlb-pr-${PR_NUMBER}.ghpublic.pwrdrvr.com" - NLB_DEMOAPP_URL="https://lambdadispatch-nlb-demoapp-pr-${PR_NUMBER}.ghpublic.pwrdrvr.com" - - # Create deployment statuses for each URL - # ALB Router - gh api repos/${{ github.repository }}/deployments \ - -F ref=${{ github.event.pull_request.head.ref }} \ - -F environment="ALB Router" \ - -F auto_merge=false \ - -F required_contexts=[] | jq .id > deployment_id_alb_router.txt - - ALB_ROUTER_ID=$(cat deployment_id_alb_router.txt) - gh api repos/${{ github.repository }}/deployments/$ALB_ROUTER_ID/statuses \ - -F state=success \ - -F environment_url=$ALB_ROUTER_URL \ - -F description="ALB Router URL" \ - -F log_url=$ALB_ROUTER_URL - - # ALB Demo App - gh api repos/${{ github.repository }}/deployments \ - -F ref=${{ github.event.pull_request.head.ref }} \ - -F environment="ALB Demo App" \ - -F auto_merge=false \ - -F required_contexts=[] | jq .id > deployment_id_alb_demoapp.txt - - ALB_DEMOAPP_ID=$(cat deployment_id_alb_demoapp.txt) - gh api repos/${{ github.repository }}/deployments/$ALB_DEMOAPP_ID/statuses \ - -F state=success \ - -F environment_url=$ALB_DEMOAPP_URL \ - -F description="ALB Demo App URL" \ - -F log_url=$ALB_DEMOAPP_URL - - # NLB Router - gh api repos/${{ github.repository }}/deployments \ - -F ref=${{ github.event.pull_request.head.ref }} \ - -F environment="NLB Router" \ - -F auto_merge=false \ - -F required_contexts=[] | jq .id > deployment_id_nlb_router.txt - - NLB_ROUTER_ID=$(cat deployment_id_nlb_router.txt) - gh api repos/${{ github.repository }}/deployments/$NLB_ROUTER_ID/statuses \ - -F state=success \ - -F environment_url=$NLB_ROUTER_URL \ - -F description="NLB Router URL (Port ${PR_NUMBER})" \ - -F log_url=$NLB_ROUTER_URL - - # NLB Demo App - gh api repos/${{ github.repository }}/deployments \ - -F ref=${{ github.event.pull_request.head.ref }} \ - -F environment="NLB Demo App" \ - -F auto_merge=false \ - -F required_contexts=[] | jq .id > deployment_id_nlb_demoapp.txt - - NLB_DEMOAPP_ID=$(cat deployment_id_nlb_demoapp.txt) - gh api repos/${{ github.repository }}/deployments/$NLB_DEMOAPP_ID/statuses \ - -F state=success \ - -F environment_url=$NLB_DEMOAPP_URL \ - -F description="NLB Demo App URL (Port ${PR_NUMBER}+10000)" \ - -F log_url=$NLB_DEMOAPP_URL - - echo "Created deployment status checks with URLs for all endpoints" + echo "alb_router=https://lambdadispatch-pr-${PR_NUMBER}.ghpublic.pwrdrvr.com" >> $GITHUB_OUTPUT + echo "alb_demoapp=https://lambdadispatch-demoapp-pr-${PR_NUMBER}.ghpublic.pwrdrvr.com" >> $GITHUB_OUTPUT + echo "nlb_router=https://lambdadispatch-nlb-pr-${PR_NUMBER}.ghpublic.pwrdrvr.com" >> $GITHUB_OUTPUT + echo "nlb_demoapp=https://lambdadispatch-nlb-demoapp-pr-${PR_NUMBER}.ghpublic.pwrdrvr.com" >> $GITHUB_OUTPUT + + - name: Find Deployment URLs Comment + uses: peter-evans/find-comment@v3 + id: find-comment + with: + issue-number: ${{ github.event.pull_request.number }} + comment-author: 'github-actions[bot]' + body-includes: '### ๐Ÿš€ Deployment URLs' + + - name: Post Deployment URLs Comment + uses: peter-evans/create-or-update-comment@v4 + with: + comment-id: ${{ steps.find-comment.outputs.comment-id }} + edit-mode: replace + issue-number: ${{ github.event.pull_request.number }} + body: | + ### ๐Ÿš€ Deployment URLs + + #### Application Load Balancer (ALB) + - **Router**: [${{ steps.generate-urls.outputs.alb_router }}](${{ steps.generate-urls.outputs.alb_router }}) + - **Demo App**: [${{ steps.generate-urls.outputs.alb_demoapp }}](${{ steps.generate-urls.outputs.alb_demoapp }}) + + #### Network Load Balancer (NLB) + - **Router (Port ${{ github.event.pull_request.number }})**: [${{ steps.generate-urls.outputs.nlb_router }}](${{ steps.generate-urls.outputs.nlb_router }}) + - **Demo App (Port ${{ github.event.pull_request.number }}+10000)**: [${{ steps.generate-urls.outputs.nlb_demoapp }}](${{ steps.generate-urls.outputs.nlb_demoapp }}) + + *Deployment updated: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}* + + # Create a single environment for the main deployment URL to show in PR checks + - name: Update Main Environment + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + # This will update the environment URL that appears in the PR checks + echo "Deployment URLs have been posted as a comment" From 6049140c9cd5702e1a2772e6b7a24f1a3897d3e0 Mon Sep 17 00:00:00 2001 From: Harold Hunt Date: Sat, 15 Mar 2025 16:29:47 -0400 Subject: [PATCH 3/3] Add docs route --- .github/workflows/build.yml | 38 ++++++++ src/demo-app/app.cjs | 175 ++++++++++++++++++++++++++++++++++++ 2 files changed, 213 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2e04a09a..4ed5ed7b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -763,6 +763,44 @@ jobs: - **Router (Port ${{ github.event.pull_request.number }})**: [${{ steps.generate-urls.outputs.nlb_router }}](${{ steps.generate-urls.outputs.nlb_router }}) - **Demo App (Port ${{ github.event.pull_request.number }}+10000)**: [${{ steps.generate-urls.outputs.nlb_demoapp }}](${{ steps.generate-urls.outputs.nlb_demoapp }}) + ### ๐Ÿงช Test Endpoints + + #### Basic Tests + ```bash + # Simple ping test + curl -v ${{ steps.generate-urls.outputs.alb_router }}/ping + + # View request headers + curl ${{ steps.generate-urls.outputs.alb_router }}/headers + + # Delayed response (milliseconds) + curl ${{ steps.generate-urls.outputs.alb_router }}/delay?delay=500 + ``` + + #### Load/Performance Tests + ```bash + # Ping test with 100 concurrent requests (Hey) + hey -h2 -c 100 -n 10000 ${{ steps.generate-urls.outputs.alb_router }}/ping + + # Ping test with controlled concurrency (oha) + oha -c 20 -z 60s ${{ steps.generate-urls.outputs.alb_router }}/ping + + # Post and echo data + curl -X POST -H "Content-Type: text/plain" --data "Hello World" ${{ steps.generate-urls.outputs.alb_router }}/echo + ``` + + #### Advanced Features + ```bash + # Chunked/streaming response + curl ${{ steps.generate-urls.outputs.alb_router }}/chunked-response + + # Read from S3 + curl ${{ steps.generate-urls.outputs.alb_router }}/read-s3 + + # Read from DynamoDB + curl ${{ steps.generate-urls.outputs.alb_router }}/read + ``` + *Deployment updated: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}* # Create a single environment for the main deployment URL to show in PR checks diff --git a/src/demo-app/app.cjs b/src/demo-app/app.cjs index 3ba8221d..2e51b47b 100644 --- a/src/demo-app/app.cjs +++ b/src/demo-app/app.cjs @@ -98,6 +98,181 @@ export async function performInit() { // Serve static files from the "public" directory app.use('/public', express.static(path.join(__dirname, 'public'))); +app.get('/', (req, res) => { + // HTML for the documentation page + const html = ` + + + + + Lambda Dispatch Demo App + + + +

Lambda Dispatch Demo App

+

This application demonstrates various features of the Lambda Dispatch system. Use the endpoints below to test different aspects of the service.

+ +

Health and Status Endpoints

+ +
+

GET /health-quick

+

Quick health check that doesn't wait for initialization.

+
curl ${req.protocol}://${req.headers.host}/health-quick
+
+ +
+

GET /health

+

Full health check that ensures initialization is complete (waits for ${initSleepMs}ms).

+
curl ${req.protocol}://${req.headers.host}/health
+
+ +
+

GET /ping

+

Simple ping endpoint that returns "pong".

+
curl ${req.protocol}://${req.headers.host}/ping
+

Load test with hey:

+
hey -h2 -c 100 -n 10000 ${req.protocol}://${req.headers.host}/ping
+
+ +
+

GET /headers

+

Returns all HTTP headers from the incoming request as JSON.

+
curl ${req.protocol}://${req.headers.host}/headers
+
+ +

Delay and Streaming Endpoints

+ +
+

GET /delay

+

Delays the response by the specified number of milliseconds.

+
curl ${req.protocol}://${req.headers.host}/delay?delay=500
+
+ +
+

GET /chunked-response

+

Returns a chunked response with an initial payload, 5 second delay, then final payload.

+
curl ${req.protocol}://${req.headers.host}/chunked-response
+
+ +

Echo Endpoints

+ +
+

POST /echo

+

Streams the request body directly to the response with back pressure.

+
curl -X POST -H "Content-Type: text/plain" --data "Hello World" ${req.protocol}://${req.headers.host}/echo
+

Debug mode:

+
curl -X POST -H "Content-Type: text/plain" -H "X-Lambda-Dispatch-Debug: true" --data "Hello World" ${req.protocol}://${req.headers.host}/echo
+
+ +
+

POST /echo-slow

+

Reads the entire request body into memory before sending the response.

+
curl -X POST -H "Content-Type: text/plain" --data "Hello World" ${req.protocol}://${req.headers.host}/echo-slow
+
+ +
+

POST /double-echo

+

Echoes each chunk of the request body twice, doubling the response size.

+
curl -X POST -H "Content-Type: text/plain" --data "Hello World" ${req.protocol}://${req.headers.host}/double-echo
+
+ +
+

POST /half-echo

+

Echoes half of each chunk of the request body, halving the response size.

+
curl -X POST -H "Content-Type: text/plain" --data "Hello World" ${req.protocol}://${req.headers.host}/half-echo
+
+ +
+

ALL /debug

+

Returns the request line, headers, and body. Works with any HTTP method.

+
curl -X POST -H "Content-Type: text/plain" --data "Hello World" ${req.protocol}://${req.headers.host}/debug
+
+ +

AWS Service Endpoints

+ +
+

GET /read-s3

+

Reads an image file from S3 and returns it. Good for testing larger payloads.

+
curl -o image.jpg ${req.protocol}://${req.headers.host}/read-s3
+

Load test with hey:

+
hey -h2 -c 100 -n 1000 ${req.protocol}://${req.headers.host}/read-s3
+
+ +
+

GET /read

+

Reads a random item from DynamoDB.

+
curl ${req.protocol}://${req.headers.host}/read
+

Load test with k6:

+
k6 run k6/read-dynamodb-constant.js
+
+ +
+

GET /odd-status

+

Returns an unusual HTTP status code (519).

+
curl -i ${req.protocol}://${req.headers.host}/odd-status
+
+ +

Static Files

+ +
+

GET /public/silly-test-image.jpg

+

Serves a static image file stored in the application.

+
curl -o local-image.jpg ${req.protocol}://${req.headers.host}/public/silly-test-image.jpg
+
+ + +`; + + res.send(html); +}); + app.get('/health-quick', async (req, res) => { res.send('OK'); });