I have the following Node.JS (runtime v6.10) executing on AWS Lambda:
exports.handler = (event, context) => {
send(event);
};
var flota = ['CZWF64', 'DRZY65', 'DRZY66', 'FPBS85', 'FPBS86', 'FPBS87'];
function send(json) {
var ppu = json.vehiculo.patente.replace(/[^a-z0-9]/gi, '');
if (flota.indexOf(ppu) == -1) {
return;
}
var request = require('request');
var url = 'http://endpointUrl';
var gps = json.gps;
var date = new Date(gps.fecha);
var month = date.getMonth() + 1;
var day = date.getDate();
var hour = date.getHours();
var min = date.getMinutes();
var month = (month < 10 ? "0" : "") + month;
var day = (day < 10 ? "0" : "") + day;
var hour = (hour < 10 ? "0" : "") + hour;
var min = (min < 10 ? "0" : "") + min;
var propertiesObject = {
aplicacion: 1802, // ID Waypoint
imei: ppu,
lat: gps.lat,
lon: gps.lon,
alt: gps.alt,
vel: gps.speed,
rumbo: gps.cog,
fecha: date.getFullYear() + month + day,
hora: hour + min
};
request({
url: url,
qs: propertiesObject
}, function(err, response, body) {
var success = false;
var error;
if (response.statusCode != 200) {
error = new Error('Get response: ' + response.statusCode);
} else if (err) {
error = new Error('[ERROR]: ' + err);
} else if (( body.indexOf('IMEI') != -1 && body.indexOf('registrada') != -1) || body.indexOf('ERROR') != -1) {
error = new Error('[ERROR]: ' + body);
} else if ('OK'.localeCompare(body) == 0) {
success = true;
} else {
error = new Error('[ERROR]: ' + body);
}
if (!success) {
throw error;
}
});
}
And as AWS Lambda charges it's costs per execution time, I'd like to improve the above code the fastest possible execution time.
Any tips would be appreciated.
PS: Is there an actual way to profile Node.JS running in AWS Lambda to inspect the possible bottlenecks?
First approach:
This code is no longer needed, as it has been externalized to the AWS IoT rule condition that invokes the Lambda function, so less invocations are done.
var ppu = json.vehiculo.patente.replace(/[^a-z0-9]/gi, '');
if (flota.indexOf(ppu) == -1) {
return;
}
Second improvement
Move constants out of the function:
var request = require('request');
var url = 'http://endpointUrl';
Third approach:
Changed if/else if order as HTTP code 200 should cover most cases:
if (response.statusCode == 200) {
if ('OK'.localeCompare(body) == 0) {
success = true;
} else if (err) {
error = new Error('[Response ERROR]: ' + err);
} else if ((body.indexOf('IMEI') != -1 && body.indexOf('registrada') != -1) || body.indexOf('ERROR') != -1) {
error = new Error('[ERROR]: ' + body);
} else {
error = new Error('[Unknown ERROR]: ' + body);
}
} else {
error = new Error('HTTP response: ' + response.statusCode);
}
3 Answers 3
Is there an actual way to profile Node.JS running in AWS Lambda to inspect the possible bottlenecks?
Node Lambdas are just small Node modules. Profiling it shouldn't be any different than any other Node app. All you need is a "wrapper" app that imports your lambda script and calls handler
with a fake event
and context
.
Your biggest enemy here won't be your code. You can only do so little with your script actually. The only bottleneck I see is that network request and that external dependency. Just ensure that endpoint responds fast.
Instead of using the request
module, consider using the built-in url.format()
and http.get
to construct your url and do a GET request, respectively. This would remove your only dependency, whose implementation you have no control of, and probably uses both built-in modules anyways.
Also, if you have control over that endpoint, its response needs fixing. A 200
should always be successful. There shouldn't be a 200
that carries an error. Common errors include 500
(generic server error), 400
(bad input), 401
or 403
(Auth errors). Following correct headers, this would allow you to skip all the conditionals and let the status codes explain themselves. Optional body text may be added to explain the status code.
-
\$\begingroup\$ The "request" module was used for the sake of clean upfront implementation, which now can be tweaked to make it better, but with proper measurements, to insure changes are actually better. Regarding the endpoint, I’m aware it’s the biggest pitfall, and even worse, at it’s from a customer, not ours. \$\endgroup\$gvasquez– gvasquez2018年03月08日 16:26:49 +00:00Commented Mar 8, 2018 at 16:26
Your code looks very clean. I am not sure there is much to improve on, especially after your third improvement. It seems you are looking for millisecond, sub millisecond improvement. One area of improvement would be switch to a compiled language to be more performant.
Check out the Latest performance stats by language for AWS Lambda.
-
\$\begingroup\$ Did so! Moved to Java and, now getting lower and more constant execution times. \$\endgroup\$gvasquez– gvasquez2018年03月11日 01:47:49 +00:00Commented Mar 11, 2018 at 1:47
mmm.. Just a guess... (I am a beginner in JS)
Instead of this..
var date = new Date(gps.fecha);
var month = date.getMonth() + 1;
var day = date.getDate();
var hour = date.getHours();
var min = date.getMinutes();
var month = (month < 10 ? "0" : "") + month;
var day = (day < 10 ? "0" : "") + day;
var hour = (hour < 10 ? "0" : "") + hour;
var min = (min < 10 ? "0" : "") + min;
How about using Moment.js ? :|
-
\$\begingroup\$ Trying no to use modules, as the are "black boxes", but I might need to measure it’s performance \$\endgroup\$gvasquez– gvasquez2018年03月08日 16:28:10 +00:00Commented Mar 8, 2018 at 16:28
Explore related questions
See similar questions with these tags.
===
and!==
as they are slightly faster. Add"use strict";
directive to the top of code as strict mode code runs faster. Don't move constants out but keeprequire("request")
out as that can be very expensive call you want to limit. And you may get tiny improvement if you throw error egerror = new Error('[Unknown ERROR]: ' + body);
becomesthrow new Error('[Unknown ERROR]: ' + body);
that way you dont need varssuccess
anderror
and the last statementif(!success){ throw error }
can be removed \$\endgroup\$