How to do hot code reloading with local lambda runtime interface emulator

The issue

When developing code for lambda functions deployed as container images you will come across the AWS Lambda Runtime Interface Emulator (RIE). The readme of its corresponding GitHub repo at https://github.com/aws/aws-lambda-runtime-interface-emulator describes how to this tool in Docker Containers. Unfortunately the tool doesn’t support hot code reloading. This means even if you have mounted your source code into your Docker Container the tool (named as aws-lambda-rie) won’t recognize code changes. So either you will restart the container every time you make code changes or find a solution to overcome this issue:

The solution

As I’m not able to see the source code of aws-lambda-rie I can’t modify it. As a consequence I have created a wrapper script which kills and starts aws-lambda-rie regularly. I need to use a wrapper script as I’m using the preconfigured Docker base images from AWS available at https://gallery.ecr.aws/lambda/. In these images aws-lambda-rie is the entrypoint which means if this process is killed for whatever reason the whole container will stop. So restarting is not an option.

Of course I want to only stop and start the aws-lambda-rie when there is no incoming request which is processed currently. That’s why the wrapper script checks for established connections on port 8080 which is the default port aws-lambda-rie is listening on.

Long story short this is the bash code created by myself:

#!/bin/sh

# function which restarts the lambda rie process after checking for established/open connections on port 8080
restart_lambda_rie_process() {
  echo "restart_lambda_rie_process() called"
  while lsof -i tcp:8080 | grep -q "ESTABLISHED" # wait till current lambda invocation is finished
  do
    echo "Lambda request is processed currently. Waiting 5 seconds and retry it again."
    sleep 5
  done

  if ! lsof -i tcp:8080 | grep -q "ESTABLISHED"; then # additional check if there is no lambda invocation running currently
    echo "Now trying to kill lambda rie process."
    PID=$(lsof -t -i:8080)
    if [ -z "$PID" ]
    then
      echo "No PID for lambda rie found!"
    else
      echo "Killing PID $PID"
      kill $PID
      echo "sleeping 5 seconds to wait for process termination..."
      sleep 5
    fi
  else
    echo "Another lambda invocation has been started in the meanwhile. Waiting of terminating the lambda rie process."
    restart_lambda_rie_process
  fi
}

# endless loop keeps container running and restarts lambda rie in regular intervals
while true  
do  
  if [ $# -ne 1 ]; then
    echo "Entrypoint requires the handler name to be the first argument" 1>&2
    exit 142
  fi
  export _HANDLER="$1"

  RUNTIME_ENTRYPOINT=/var/runtime/bootstrap
  if [ -z "${AWS_LAMBDA_RUNTIME_API}" ]; then
    exec /usr/local/bin/aws-lambda-rie $RUNTIME_ENTRYPOINT &
  else
    exec $RUNTIME_ENTRYPOINT
  fi
  echo "Sleeping 10 seconds to avoid unnecessary process restarts..."
  sleep 10
  restart_lambda_rie_process
done


Sidenotes:

When working with AWS lambda rie I couldn’t find documentation about the parameters supported by the tool aws-lambda-rie itself.

But it looks like you can give it a few parameters and people are working on it, e.g.:

https://github.com/aws/aws-lambda-runtime-interface-emulator/pull/153