I'm having problem with a Lambda function which for some reason it goes on timeout.
I tried to add some console.log to understand what was going on and everything works properly until the external http request.
I use the npm module request
I can see the log before the request, but the one inside the callback never shows up, like if the endpoint doesn't respond.
Am I missing something? Thanks in advance!
var mysql = require('mysql');
var request = require('request');
var config = require('./config.json');
var pool = mysql.createPool({
host: config.dbhost,
user: config.dbuser,
password: config.dbpassword,
database: config.dbname
});
var openWeatherOptions = (device) => {
let domain = 'https://api.openweathermap.org/data/2.5/';
let apiEndpoint = 'weather?';
let params = `lat=${device.lat}&lon=${device.lng}&APPID=${process.env.WEATHER_APP_ID}&units=metric`;
let url = [domain, apiEndpoint, params].join('').toString();
return {
url: url,
method: 'GET',
headers: { 'Content-Type': 'application/json'},
};
};
exports.handler = (event, context, callback) => {
context.callbackWaitsForEmptyEventLoop = false;
// Connect to DB
console.log('fallback connecting to DB')
pool.getConnection( (errOnConnection, connection) => {
if(errOnConnection) {
callback({"err": errOnConnection });
}
console.log('fallback connected to DB')
// Retrieve device position
let queryOne = 'SELECT lat, lng FROM T03_DevicesPosition WHERE deviceCode = (?);';
console.log('fallback retrieving device position')
connection.query( queryOne, [event.device], (errOnQ1, results, fields) => {
if(errOnQ1) {
connection.release();
callback({"err": errOnQ1 });
}
console.log('fallback device position retrieved')
// Call openweather
let device = results[0];
let options = openWeatherOptions(device);
console.log('fallback calling openWeather with following data: ', device, options);
request( options, (errOpenWeather, response, body) => {
console.log('fallback openweather response received');
if(errOpenWeather || (response.statusCode !== 200 && response.statusCode !== 201) ) {
connection.release();
callback({"err": errOpenWeather });
}
let meteo = JSON.parse(body).main;
meteo.date = new Date(event.time*1000);
meteo.pressure = Math.floor( meteo.pressure );
console.log('fallback storing data', meteo);
let query = `INSERT INTO T02_DevicesTransmissions (deviceCode, transmissionDate, temperature, humidity, pressure, unixDate, rawData) VALUES ( ?, ?, ?, ?, ?, ?, ?);`;
let queryValues = [ event.device, meteo.date, meteo.temp, meteo.humidity, meteo.pressure, event.time, 'fallback'];
connection.query( query, queryValues, (errInsert, results, fields) => {
connection.release();
console.log('fallback completed with', errInsert ? '' : 'out');
if (errInsert) callback({"err": errInsert });
else callback();
});
});
});
});
}
This is an old question but I spent a few hours banging my head figuring out how to set this up properly, so here's hoping someone else's time will be saved :)
If your lambdas are in a VPC they need to go through a NAT Gateway in order to reach external services.
One way to achieve this is:
target
field)This will route traffic from your lambdas properly through the NAT and Internet Gateway so they can reach external services.
Note that if you're also using RDS from your lambdas AND you intend to also connect to RDS from outside (e.g. to manage the DB from your local machine), you can't put the RDS instance in the lambdas' subnet, or you won't be able to connect to it from outside (the NAT is outbound only). In that case you should make sure your RDS instance is associated with a subnet that is accessible, for instance the one the NAT is in (i.e. the one that sends outbound traffic to the Internet Gateway).