David D David D - 29 days ago 12
Node.js Question

Bluebird with Lambda not returning data

We have a simple query to fetch information from our database using a serverless application deployed on nodejs. Unfortunately I am not able to get any responses from Bluebird promise - the response always timesout and I'm not sure what could be causing the issue. Below are my files:

serverless.yml:

service: myAuth0

provider:
name: aws
iamRoleARN: arn:aws:iam::XXXXXXXXX:role/test-role
runtime: nodejs4.3
stage: production
region: us-us-1
iamRoleStatements:
- Effect: "Allow"
Action:
- "ec2:CreateNetworkInterface"
- "ec2:DescribeNetworkInterfaces"
- "ec2:DeleteNetworkInterface"
Resource: "*"
vpc:
securityGroupIds:
- ${self:custom.${opt:stage, self:provider.stage}.${opt:region, self:provider.region}.vpc.securitygroup}
subnetIds:
- ${self:custom.${opt:stage, self:provider.stage}.${opt:region, self:provider.region}.vpc.subnet1}
- ${self:custom.${opt:stage, self:provider.stage}.${opt:region, self:provider.region}.vpc.subnet2}

custom:
production:
us-east-1:
vpc:
subnet1: subnet-11111111
subnet2: subnet-22222222
securitygroup: sg-33333333

functions:
getUserRoles:
handler: app/handler.handle
events:
- http:
method: get
path: userstest/roles


handler.js:

'use strict';

require('dotenv').config();
var Promise = require('bluebird');
var getConn = require('./dbConn');

module.exports.handle = (event, context, callback) => {
Promise.using(getConn(), function(conn){
return conn.query('select ert.name from emp_roles ert order by ert.name').then(function(rows){
let roles = [];
rows.forEach(function(row){
roles.push(row.name);
});
return roles;
}).catch(function(err){
console.log(error);
});
}).then(function(roles){
console.log("found roles: " + roles);
callback(null, {roles: roles});
});
};


dbConn.js:

var mysql = require('promise-mysql');
var pool = mysql.createPool({
connectionLimit: 10,
host : process.env.MYSQL_HOST,
user : process.env.MYSQL_USER,
password : process.env.MYSQL_PW,
database : process.env.MYSQL_DB
});

function getConn() {
return pool.getConnection().disposer(function(connection) {
pool.releaseConnection(connection);
});
}

module.exports = getConn;


I added console log entries and I can see that it completes them...however it does not return anything and I end up with a connection error. I see that the data is fetched and Lambda just sits there without returning anything for 6 seconds. Below is the latest entry from cloud watch:


18:15:01 START RequestId: 195a7218-a516-11e6-b52d-5f028bb2bdf6
Version: $LATEST 18:15:01 2016-11-07T18:15:01.820Z
195a7218-a516-11e6-b52d-5f028bb2bdf6 found roles: 9 18:15:07 END
RequestId: 195a7218-a516-11e6-b52d-5f028bb2bdf6 18:15:07 REPORT
RequestId: 195a7218-a516-11e6-b52d-5f028bb2bdf6 Duration: 6002.14 ms
Billed Duration: 6000 ms Memory Size: 1024 MB Max Memory Used: 18 MB
18:15:07 2016-11-07T18:15:07.468Z 195a7218-a516-11e6-b52d-5f028bb2bdf6
Task timed out after 6.00 seconds


Is there something that breaks when using Bluebird with Lambda?

Answer

Bluebird definitely works.

I think there might be a problem with ending connection using disposer. I use postgresql promise library so can't really try with mysql but I rewritten it to use disposer and I get same timeout.

Try ending connection in your finally block.

db.getConnection()
  .then(doMyQuery)
  .catch(catchErrors)
  .finally(db.disposeConnection)

EDIT: Ok, actually releasing connections is bad in lambdas, you should be ending them. mysqljs docs say:

When you are done with a connection, just call connection.release() and the connection will return to the pool, ready to be used again by someone else.

You don't really want that. That's why you get a timeout. When your promise chain ends, the connection returns to the pool and WAITS to be used again, thus lambda timeouts since it's never ending.

Use connection.end() or connection.destroy()