PHP ON LAMBDA

WITH CUSTOM RUNTIMES

PHP UK Conference 2023

Ian Littman / @ian@phpc.social / @iansltx

Follow along at https://ian.im/lambuk23

Questions We'll Answer

  • Why you'd use Lambda, and what caveats come with using it
  • How Lambda works with Custom Runtimes (including PHP)
  • How to build an email reply bot with Lambda, SES, S3, and PHP
  • How to build a Lambda-powered API via
    • API Gateway
    • Function URLs
  • Bonus: How to build API Gateway endpoints with Bref

Topics We won't cover

  • A deep dive into Bref or Serverless Framework
  • Building Lambda applications via AWS's CLI
  • AWS SAM
  • Laravel Vapor

WHY LAMBDA?

What kinds of integrations?

Shared-nothing-ish?

A note on performance

A note on Billing

  • Billed per GB/s, rounded to the nearest ms
  • Includes init (for custom runtimes) and execution,
    including I/O wait
  • Init phase gets you two
  • arm64 is cheaper than x86

Virtual Private Caveats

So, what about PHP on Lambda?

Layers

Custom runtime lifecycle

  • Bootstrap (cold start)
  • Task execution (warm start)
  • Lambda decides when to kill the instance
    • Inactivity timeout
    • Task deadline (configurable, up to 15 minutes)
  • Initialize runtime
  • Prep function for execution
  • Pass env vars including file/method for handler function
  • If there's an error init-ing, make an API call

Task execution (warm start) Phase

  • Call APIs to process work
  • Next invocation (GET)
    • Request ID and more in headers
    • Task data in response body, JSON-encoded
  • Invocation response (POST)
    • Request ID in URL
    • Response in body
    • Consuming services may require specific format
  • Can perform (billed) cleanup between calling response
    endpoint and requesting the next invocation

Logging & Errors

What might this look like from AWS's Side?

  1. Are any workers for target function waiting on work?
  2. If so, skip to step 3; if not...
    1. Build a new instance (container or layers + function code)
    2. Run /opt/bootstrap (or /var/task/bootstrap,
      or container entrypoint)
    3. Wait for it to do one of the following
      1. Return nonzero from the bootstrap (init failure)
      2. Call the init error API endpoint
      3. Call the task request API endpoint
  3. Respond to the next invocation endpoint with event
  4. Wait for API calls to invocation success/failure or timeout,
    whichever comes first
  1. SES rule pushes email to S3
  2. S3 triggers Lambda
  3. Lambda function executes...
    1. Grabs email from S3
    2. Parses using MIME parser
    3. RaNdOMlY CaPiTaLiZeS LEtTerS
    4. Sends email reply via SES
  1. HTTP request hits API Gateway
  2. Lambda function executes...
    1. Grabs query string parameter if there is one
    2. RaNdOMlY CaPiTaLiZeS LEtTerS
    3. Sends a JSON response
  3. API Gateway turns the Lambda payload into an HTTP response
  1. HTTP request hits function URL
  2. Lambda function executes...
    1. Grabs query string parameter if there is one
    2. RaNdOMlY CaPiTaLiZeS LEtTerS
    3. Sends a JSON response

Auth (if needed) can be done via AWS signatures

...but you should probably use Bref in prod

For Bref questions, find this guy (@matthieunapoli, @mnapoli@phpc.social)

...or go to bref.sh/docs

...or Vapor, if you're using Laravel

Thanks! Questions?