Deploying changes to individual Lambdas using Serverless Framework

I have a serverless project that deploys 2 Lambdas in the same stack:

service: example-apis2

provider:
  name: aws
  memorySize: 512
  region: us-west-1
  apiGateway:
    restApiId: ${env:APIGWID} #  API Gateway to add this api to
    restApiRootResourceId: ${env:RESOURCEID}
functions:
  example2:
    handler: index2.handler
    layers:
      - arn:aws:lambda:us-west-1:[myaccountid]:layer:example-layer:1
    events:
      - http:
          path: api2
          method: get
  example3:
    handler: index3.handler
    layers:
      - arn:aws:lambda:us-west-1:[myaccountid]:layer:example-layer:1
    events:
      - http:
          path: api3
          method: get

After first deploy, if I do

aws lambda get-function --function-name example-apis2-dev-example2 
...
"LastModified": "2021-10-27T06:30:31.002+0000",

and

$ aws lambda get-function --function-name example-apis2-dev-example3
...
"LastModified": "2021-10-27T06:30:31.987+0000",

Now if I make a code change only to the example 3 Lambda and redeploy only that function with:

serverless deploy function -f example-apis2-dev-example3

… example2 has not been modified since the first deploy (same timestamp as the original deploy):

$ aws lambda get-function --function-name example-apis2-dev-example2
...
"LastModified": "2021-10-27T06:30:31.002+0000",,

and only example3 shows it was updated/redeployed:

$ aws lambda get-function --function-name example-apis2-dev-example3
...
"LastModified": "2021-10-27T06:33:17.736+0000",

serverless deploy : deploys the whole stack (but if nothing has changed there is no update)

serverless deploy function -f functioname: updates just the code on that one Lambda (and updates in a couple of seconds vs several seconds for updating the whole stack).

This is described in this article here.

node.js, node-oracledb and Oracle Instant Client

To access an Oracle DB from an AWS Lambda function developed with node.js, you need to package you Lambda with shared libraries from Oracle’s Instant Client. The install instructions are here ( http://oracle.github.io/node-oracledb/INSTALL.html#quickstart ) but the only part that is really needed is the download location (since there’s no specific instructions for bundling the libs with an AWS Lambda): https://www.oracle.com/database/technologies/instant-client/linux-x86-64-downloads.html

Not all the Oracle Instant Client files are needed. From this older npm module to automate the packaging of the required libraries, I used this same list of required libraries:

libclntshcore.so.19.1
libclntsh.so.19.1
libmql1.so
libipc1.so
libnnz19.so
libons.so (not packaged in current Instant Client)
libociicus.so
libaio.so (from separate download - see next step)

libaio – if you’re on a Linux platform you can ‘apt-get install libaio’ or similar, but building my Lambda on a Mac I had to manually download the package and extract just the .so file from here (download the Arch Linux x64 package): https://pkgs.org/download/libaio

Put these in a /lib dir and zip up the folder and files. Use this to create a Lambda Layer.

For the Lambda itself install the node.js module for the api:

npm install –save node-oracledb

For examples in api usage, see the examples here: https://github.com/oracle/node-oracledb/tree/master/examples

Creating a new AWS Lambda using the AWS CLI

It’s pretty easy to set up and configure a new AWS Lambda with the AWS Console, but if you’re iterating on some changes and need to redeploy a few times, the AWS CLI makes it pretty easy.

To create a new Lambda, assuming you have a .zip packaged up and ready to go:

aws lambda create-function --function-name example-lambda --zip-file fileb://example-lambda.zip --handler index.handler --runtime nodejs8.10 --role arn:aws:iam::role-id-here:role/lambda-role

AWS IoT and Node.js on the Raspberry Pi

There are many approaches for installing node.js on the Raspberry Pi (Google and you’ll find lots of guides), presumably because for a while there didn’t seem to be any official binaries in the official apt repos so people were building and sharing their own.

I installed a version from somewhere (can’t actually remember where as it was a while back) and it doesn’t support ES6 class syntax used by some of the dependent libraries in the AWS IoT SDK:

$ node index.js
/home/pi/aws-iot-nodejs-pi-lights/node_modules/aws-iot-device-sdk/node_modules/mqtt/node_modules/websocket-stream/server.js:6
class Server extends WebSocketServer{
^^^^^
SyntaxError: Unexpected reserved word
    at Module._compile (module.js:439:25)
    at Object.Module._extensions..js (module.js:474:10)
    at Module.load (module.js:356:32)
    at Function.Module._load (module.js:312:12)
    at Module.require (module.js:364:17)
    at require (module.js:380:17)
    at Object.<anonymous> (/home/pi/aws-iot-nodejs-pi-lights/node_modules/aws-iot-device-sdk/node_modules/mqtt/node_modules/websocket-stream/index.js:2:14)
    at Module._compile (module.js:456:26)
    at Object.Module._extensions..js (module.js:474:10)
    at Module.load (module.js:356:32)

The version I currently have installed is:

pi@raspberrypi:~ $ node -v
v0.10.29

Since I’m not sure where this version came from originally, (and apt-get upgrade is not finding any updates), I uninstalled:

sudo apt-get remove nodejs
sudo apt-get remove npm

Then I followed the steps in the AWS IoT SDK guide here to install using the version provided from Adafruit’s repo  (official node.js binaries for ARM are also available from nodejs.org here).

With version provided from Adafruit, this gives v 0.12.6 but unfortunately this still gives the same error with the ES6 class keyword.

$ node -v
v0.12.6

Next, lets try the ARM version from nodejs.org. There’s step by step instructions here showing how to download the tar, extract and copy to /usr/local/

Now we have:

$ node -v
v8.9.1

And now trying to run my AWS IoT node.js based app, success!