Node.js: moving intensive tasks to a child process

If you have code in your Node application that runs longer than a few seconds then you should consider moving it off the main thread, especially if it is a task that you will be running many times per hour or day. Because Node is single threaded, long running processes can block other code from executing and give end users the perception that your application slow. An example of a CPU intensive task might be retrieving an RSS feed, or multiple RSS feeds, at regular intervals and then post-processing the data.

There are several different ways to handle intensive and repetitive tasks in Node, for this post I’m only going to focus on #2:

  1. External Cron Job. You can implement a server-based cron process that runs completely outside of your application process and kicks off a node application at regular intervals and then writes the results to a database or static file.
  2. Child Process. Or, you can create a new, separate process to handle your long running code and then use what’s called a ‘signal’ to pass data between the new process and your main Node application. This pattern is based on Unix/Linux signals.

There are plenty of articles on the internet that discuss how to set up cron jobs so I’m going to skip that. There are very few if any full blog articles that discuss in detail how to build an application with child processes that handle repetitive and intensive tasks. There are Stack Overflow snippets that are great, but they leave out much of the nitty-gritty of how to get everything working, especially for newb’s.

The good news is the steps for implementing a child process are fairly straightforward. The following psuedo-code snippets demonstrate the steps. You can download or fork the full source code from this github repo.

Step 1. Create a new file for the code that you want to run in a separate process. We’ll name this file retriever.js and it will contain a timer and our mock intensive task. Note that the timer doesn’t have to be in the same file, I just put it there for convenience to help illustrate my point.

I also recommend setting up a counter to keep track of the total number of errors related to sending data from retriever.js back to index.js or specifically related to your intensive task. It’s important for you to know that the child process “can” continue to run even if the parent process stops accepting signals. When this happens the child process will throw errors. By counting the number of errors associated with your task or sending/receiving you can force the child process to fail gracefully.

var timers = require("timers"),
    http = require("http")
    ___backgroundTimer;

process.on('message',function(msg){

    this._longRunningTask = function(data){
        var finalArray = []
        for(var url in data){
            //TODO do something here to create the 'result'
            finalArray.push(result);
        }

        //Send the results back to index.js
        if(finalArray != []){
            var data = {
                "error":null,
                "content":finalArray
            }

            try{
                process.send(data);
            }
            catch(err){
                console.log("retriever.js: problem with process.send() " + err.message + ", " + err.stack);
            }
        }
        else{
            console.log("retriever.js: no data processed");
        }
    }

    this._startTimer = function(){
        var count = 0;

        ___backgroundTimer = timers.setInterval(function(){

            try{
                var date = new Date();
                console.log("retriever.js: datetime tick: " + date.toUTCString());
                this._longRunningTask(msg.content);
            }
            catch(err){
                count++;
                if(count == 3){
                    console.log("retriever.js: shutdown timer...too many errors. " + err.message);
                    clearInterval(___backgroundTimer);
                    process.disconnect();
                }
                else{
                    console.log("retriever.js error: " + err.message + "\n" + err.stack);
                }
            }
        },msg.interval);
    }

    this._init = function(){
        if(msg.content != null || msg.content != "" && msg.start == true){
            this._startTimer();
        }
        else{
            console.log("retriever.js: content empty. Unable to start timer.");
        }
    }.bind(this)()

})

process.on('uncaughtException',function(err){
    console.log("retriever.js: " + err.message + "\n" + err.stack + "\n Stopping background timer");
    clearInterval(___backgroundTimer);
})

Step 2. Create a fork of the current process in index.js. The fork request is executed immediately by the application.

var childProcess = require("child_process");
this._retrieveChild = childProcess.fork("./background/retriever");

Step 3. Pass message(s) from index.js to the forked process using the send() method. Note, since the data being passed back-and-forth is automatically serialized you’ll need to use JavaScript primitives such as Object, String, Integer and Array. Any non-Primitive data will have to be manually serialized and de-serialized down to its component parts.


var _finalizedData = null,
    _httpRequestArray = ["https://someurl","https://someurl2","https://someurl3"];

var data = {
    "start":true,
    "interval": 60 * 60 * 1000,
    "content": _httpRequestArray
}

this._retrieveChild.send(data);

Step 4. Receive messages from the forked process and process them in index.js.

this._retrieveChild.on('message', function(msg){
    console.log("Recv'd message from background process.");
    _finalizedData = msg.content;
}.bind(this))

Step 5. Verify that everything works by running the application and opening it in a web page. You can also use a terminal window and grep for any node processes. If your code was implemented correctly it should run without any errors and grep show your background process running separately from node:


bash-3.2$ ps aux | grep node
andy        79497   1.2  0.1  3039268  15040 s000  S     1:27PM   0:02.87 /usr/local/bin/node --debug-brk ./samples/currentweather/utils/retriever
andy        79531   0.0  0.0  2432768    612 s000  U+    1:31PM   0:00.00 grep node

References:

Github repo: node-background-processer
Node Child Process Class
Linux Signals Fundamentals – Part 1

7 Critical Things to Know When Building Any Mobile App

This blog post builds on concepts proposed in an earlier post about not all mobile apps being created equally. If you are a developer who is in the process of migrating to mobile this post is for you. It’s intended to raise awareness of important items to consider in your requirements. My goal is to help you identify some of the major gotchas early on in the development process and improve your chances for success.

There are many more details to learn on the topics I’ve described below. The good news is that in the last few years the amount of deeply helpful documentation has expanded considerably. Where possible I’ve tried to include links related to each topic.

Touch-based Workflows. Recent research has shown that people use their smartphones more often than web apps, and they spend roughly 80% of their time on social media and games. Because of this and the fact that smartphones today are touch driven and not mouse driven, you have to take that into account in your user interface design. Touch implies many things including gestures and multi-touch. You can toss your old conceptions of user interface design based on desktops and tablets, and check out Android’s recommendations as well as Apple’s. My strong recommendation is to hire a UX designer to help you through building a user interface.

Mutliple form factors come with various screen sizes and densities. Long gone are the days of building for just three main browser types. Now you have to take into consideration iPhones, iPads, tablets, numerous different style androids as well as desktop and laptops. Android defines the following screen sizes and, as you can see, this is quite varied and smaller than a typical laptop or desktop. Those typically run 1024 x 768 or greater.

  • xlarge screens are at least 960dp x 720dp
  • large screens are at least 640dp x 480dp
  • normal screens are at least 470dp x 320dp
  • small screens are at least 426dp x 320dp

This is important to know because an app that looks good on an iPad may not look good, or display correctly, on the four inch display of a Motorola Atrix at 960 x 540. A button that looks correctly sized on one smartphone may look too big on another. A whopping 84% of all Android screens are what Android defines as normal size (>=  470dp x 320dp) and between either medium dpi (~160dpi) or high dpi (~240dpi). But, you still have to take into consideration other densities. I also recommend taking a look at new HTML5 browser-based technologies to help with addressing this problem, such as CSS media queries.

Inconsistent Internet. It’s a best practice to check if internet connections exist and gracefully handle HTTP requests when the internet is down, as I blogged about here.  Depending on your application and needs, you should also monitor whether or not a wireless connection can be made and then allow the application to switch to wireless where possible. Wireless also has the advantage of using less battery power.

Slower Connections. And, on a related note, you can’t always depend on 4G connections having consistent maximum download speeds. Over the course of a user session, the connection speed will vary widely and you should plan for that. I’ve been trying to find some stats on mobile internet quality world-wide, if they are out there they are hard to find. But, we’ve all experience spotty mobile internet coverage. Take this into account if you are transferring large amounts of data between your servers and your app. You should also consider detecting when the user is in an area of greater bandwidth and use that to download more data less often. Use loosely coupled and event driven architectures. Test app load times on various devices and around town and away from your office.

Less CPU Horsepower. While the latest generation of four core phones are certainly the most powerful phones yet. In general, applications and web pages will run slower on phones than they do on your development machine running a desktop browser. Take older generation phones into account because they are usually significantly slower than the newer phones. There are a few workarounds in HTML5 to help with this, in that done correctly they can offload rendering to the hardware. In native applications be aware of memory leaks because, remember, more memory usage means less battery life and applications that can run slower over time.

Support across multiple operating system versions. Remember on Android that the vast majority of users are still running v2.2 – v2.3.7 even though v4.x is currently shipping. You’ll have to do some research on your target market and find out what versions and type of phones they are using. You can’t support everything, but you can make educated guesses. Apple, on the other hand, has a significantly more limited selection of phones and tablets that you have to support, and they do a great job helping you support those.

There are some solutions that help with building cross-platform mobile apps, to go into more detail will take another blog post. Here’s a few: Adobe Flex, PhoneGap and Titanium. Keep in mind that the future of Flex, as a development platform, is being called into question after Adobe open sourced everything but the browser and desktop runtimes to the Apache Foundation. PhoneGap and Titanium offer what is now being called “hybrid” solutions where you can build an application in JavaScript, for example, and then compile that code for native deployments on Android and iOS.

Battery Life. Ah, battery life is last but certainly not least. Be aware of how battery intensive your application is and try to minimize battery consumption as much as possible. The Android online docs have a number of highly information articles on this subject. Smaller app footprint in memory means less battery consumption. Heavy CPU usage means more battery usage. Minimize GPS usage through smart algorithms to help preserve battery life.  Switch to 802.11 wireless connections where possible, since this requires less battery power than 3G and significantly less power than 4G.

So, there you go. I hope these suggestions help. If you have more suggestions based on your own experience please post a comment!

References:

Android Gestures

Android Optimize Battery Life

Android Screen Sizes and Densities

CSS media queries

Android UI Design

Android Model for Best GPS Performance

iOS User Experience

HTML5 Hardware Acceleration

Event-based Architectures for Adobe Flex

So you want to build a mobile app? Not all mobile apps are created equally

Most smartphones users I know ditch apps pretty quickly if they don’t work or end up being clunky. So, if your company is considering offering mobile apps to your customers you should be aware of a few things.

Buy a Smartphone. If you don’t already have a smartphone then you should go out and buy one. Then download a number of apps that interest you and try them out and see what you like and what you don’t like. For example, if you do the shopping for your family you might consider trying out a bar code scanner app that lets you compare pricing. Some scanner apps may work faster than others. If you don’t own a smartphone then you won’t be able to understand what a good app is.

Likes and Dislikes. Pay close attention to what you like and don’t like about a particular app. Here are a few questions to take note of:

  • Was it easy to use?
  • Did it hang and/or crash?
  • Did it perform its tasks gracefully?
  • Did it do what you expected?
  • Was it visually appealing?

Become Tech Savvy. Become a bit more tech savvy about things that the phone is doing behind the scene. There are apps that do this for both Android and iPhone that help you monitor what’s going one. Things to look out for:

  • Apps that keep running even after you think you shut them off. These will run the battery down faster.
  • Apps that consume more and more memory over time. Using more memory equals more battery usage and shorter time between charges.
  • Apps that seem to slow your phone down when they run. These apps may be using more CPU than necessary resulting in greater battery usage.
  • Apps that connect to the internet frequently costing you extra data charges. There are apps that let you monitor how much data your phone uses and some apps can help pinpoint which apps use the most data.

Which Phones to Support? Understand what devices to support. If you are building an application for internal use, then you have an easier decision since you hopefully have some control over which devices are being used and how often their software gets updated. If you work in retail, your users may have Androids, Blackberries, iPhones, iPads, Kindle’s, Nook’s and possibly other tablets that get updated whenever and however the customer dictates. My advice is do some research and pick one that is used the most and work on that first.

Release Early and Iterate Often. Technology changes so quickly these days that if your app takes more than 3 – 6 months to build, then the technology will change underneath you. In other words, you might be releasing an application that doesn’t work perfectly with the latest phone operating systems or browsers that your customers are using. When that happens, it will cost you even more time and money to fix the problem and the problem will repeat itself. Be sure to take into account the speed at which technology will change once you begin your software development process.

Go Native, Go Web Browser, or Both? Last, it’s important to understand that there are two common types of mobile applications. Native apps are downloaded from an app store and installed directly on the phone, the other is a web app that runs in the phones web browser. My advice is to research and understand your target market. What do your competitors use? What do your customers prefer? What are the trends in your industry?

If you go with native apps, you’ll need to understand which phones to support and how often you will be updating the app. If you choose web apps you’ll need to know which browsers to support. Also take into consideration which skill sets your development team has and understand if they can tackle the project or if you need outside help.

Update, Update, Update. No matter what you decide, you can’t just deploy an app and think you’re done. If you want to keep your customers happy, you’re going to have to keep updating the app until the product line is discontinued or replaced. And, you have to update it often enough to stay on top of the latest technologies. New smartphone models are being released all the time and they all may have different screen sizes and screen resolutions. An app that looks good at one screen size may look horrible on a tablet or iPad. These things have to be accounted for. And, the smartphones operating system software may be updated three or more times per year offering new functionality and fixing bugs. If your customers download a broken app, or if they see the app that hasn’t been updated in a while and something stops working they may not be your customers for much longer. This is especially true for retail apps where customers make split second decisions whether to stay or walk away and try something else.

Conclusion. I hope you find this list useful and at least give you some ideas to think about before you dive head first into bringing a new mobile application into the world. It can be fun, be there is a lot of hard work involved. But, if you plan it right you’ll be successful and learn alot in the process!