David D David D - 1 year ago 74
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 Source

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()

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download