3
\$\begingroup\$

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);
}
\$\endgroup\$
1
  • 1
    \$\begingroup\$ Not much room to optimize. Use === 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 keep require("request") out as that can be very expensive call you want to limit. And you may get tiny improvement if you throw error eg error = new Error('[Unknown ERROR]: ' + body); becomes throw new Error('[Unknown ERROR]: ' + body); that way you dont need vars success and error and the last statement if(!success){ throw error } can be removed \$\endgroup\$
    – Blindman67
    Commented Mar 8, 2018 at 7:57

3 Answers 3

1
\$\begingroup\$

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.

\$\endgroup\$
1
  • \$\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
    Commented Mar 8, 2018 at 16:26
1
\$\begingroup\$

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.

\$\endgroup\$
1
  • \$\begingroup\$ Did so! Moved to Java and, now getting lower and more constant execution times. \$\endgroup\$
    – gvasquez
    Commented Mar 11, 2018 at 1:47
0
\$\begingroup\$

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 ? :|

\$\endgroup\$
1
  • \$\begingroup\$ Trying no to use modules, as the are “black boxes”, but I might need to measure it’s performance \$\endgroup\$
    – gvasquez
    Commented Mar 8, 2018 at 16:28

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.