PHP ON LAMBDA

WITH CUSTOM RUNTIMES

ConFoo Montreal 2020

Ian Littman / @iansltx

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

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
  • 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

  • CPU speed scales with RAM allotment
    • Minimum: 128 MB
    • Maximum: 3008 MB
    • Increment size: 64 MB
    • At 1792 MB you have one full core (stop there)
  • Using Serverless (e.g. via Bref)? Default is 1024 MB
  • There are a few other limits to keep in mind

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 (~10 minutes)
    • 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

Logging & Errors

  • Invocation error (POST)
  • STDOUT -> CloudWatch Logs
  • Metrics available via CloudWatch (or in function UI)

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 (layers + function code)
    2. Run /opt/bootstrap (or /var/task/bootstrap)
    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

...but you should probably use Bref in prod

...or Vapor for Laravel-ites

returntrue.win uses Bref

Further Reading

Thanks! Questions?