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

6 myths on migrating from web to mobile

If you have a public facing website today, then it should be mobile enabled. Period. In this post when I say mobile I’m referring to both native and web mobile. There are an endless variety of articles discussing the benefits of moving from web to mobile, however there are very few articles on the internet that discuss the costs of migrating from a traditional web software development environment to mobile. And, yes, in 2013 there are still some major and not-so major companies that haven’t migrated to mobile. I think the best way to start talking about costs is to expose some common myths.

These myths are more about discussing the impact of not “going mobile” and adjusting to an increasingly mobile-friendly world. Consider your users to be the experts on what the mobile experience should or shouldn’t be like. Remember, building mobile web sites and apps in 2013/2014 is about accommodating usage patterns that many, many users have already adopted and are intimately familiar with. This is okay, but you’ll need to play by the rules already established by thousands of other companies and organizations that have already built mobile apps.  Don’t play and it could mean lost customers and slower business growth.

Myth #1 – Mobile, we don’t need no stinkin’ mobile. The sheer number of mobile devices in circulation is a hard, cold fact. There’s hundreds of millions of them. And rest assured these devices are well loved and used constantly 24 x 7 by their adoring owners. Smartphone and tablet sales worldwide have finally started to outnumber desktop sales. Along with the shift to mobile, the use cases have changed in a significant way. Think about this: desktop use cases only apply when you are sitting at your desk or crack open a laptop. In comparison, mobile devices go with us wherever we go and we can access them anytime and almost anywhere: such as standing in line at the grocery store, waiting for dinner at a restaurant, getting real-time driving directions and the list goes on and on. The very nature of having a device with you all the time, even when you go to bed, lends to its ease-of-access.

Myth #2 – Squeeze existing content onto a smaller screen. Don’t do it. It can lead to awful and sometimes nearly unusable navigation and surfing experiences. Users who spend many hours a day looking at their mobile devices and visiting dozens or hundreds of sites and apps that are mobile-ready will absolutely expect your content to be mobile compliant.  For this reason major phone OS vendors have spent a lot of time and money to publish user interface guidelines.

Myth #3 – Continue to use long development cycles. The mobile world changes fast. Prototyping should occur in hours, days or weeks rather than months or years. Full release cycles are  often measured in months. To get an idea of the pace of change check out how fast updates occur to the Android operating system. I’ve gotten feedback on some companies with mobile development cycles being planned for up to 1.5 years from design to delivery of v1.0. In today’s fast paced world that can be a sure bet for problems and increased risk of project failure.

Myth #4 – Recreate complex workflows on smaller screens. Mobile device workflows call for simplified, intuitive workflows with fewer steps. If you have what I’ll call an enterprise web app with dozens of menus and pullouts, pulldowns and multiple pages then you’ll need to do some homework along side a good user interface designer to figure out how to make it work on mobile. Chances are your app will have to be sliced and diced into smaller and more digestible chunks.

Myth #5 – Reuse existing security measures on mobile. Mobile security is vastly different than desktop security and applying desktop security patterns to mobile can be a recipe for disaster.  People carry their devices everywhere and they tend to download many different apps, and some people don’t even use their screen lock. We’ve all heard stories of devices being left unattended in public places or left behind at airport security screening.  So, there are many more ways for potentially serious security breaches to happen via mobile devices than your typical laptop.

Myth #6 – Users won’t like change. If you have a public facing web site today that’s not mobile compliant, chances are you’ll have a significant portion of your mobile users who aren’t happy. The best way to find out: survey. Ask your users what they think…don’t leave it to guesswork and opinions. Get the facts from the people who matter most: your customers. And, I’m going to go out on a limb and say that the majority of users would jump at the chance to use a mobile version of your website.

References

iOS Version History
Android Version History
WindowsPhone Version History
iOS User Interface Guidelines
Andriod User Interface Guidelines

Web developers: 10 ways to deal with intermittent connections

This post is about web applications designed for online-only usage that for reasons beyond your control will occasional go offline, or appear to have connection problems to non-techy end users. Even though we expect it, connectivity is not guaranteed. The good news: there are many things that you can control to help improve the usability of your sites and the perception of its uptime.

The Internet is inherently unreliable and it goes up and down as well as faster and slower all the time. It’s even more unreliable if you are talking about mobile web as compared to being plugged into a dedicated Ethernet or WiFi connection. Failures can happen within the app, on the Internet connection and even at the web server or CDN and when it happens it can frustrate users and eventually turn them into unhappy customers. The challenge for you as web developers and IT managers: it’s often hard for the people managing websites to get a real good look at the end-user experience because it can be so hard to duplicate.

In general most users typically blame their “internet connection” which is a euphemism for it’s the cellphone providers fault or the DSL or cable company’s fault. And, most people don’t know or really care where the problem is, they just want it fixed.  A common reflex when there is a problem is for a user to simply reload the entire page. In some cases, a full page reload isn’t possible or it’s painful such as more complex sites where a full reload means potentially walking about through several steps to get to back to the final page or view.

So here are a few suggestions to you, as a web developer, to help minimize occasional disruptions and keep users as happy as possible. Some of these are major repeats but they are well worth seeing yet again:

Performance. Make your web pages as lightweight as possible. Pages that load faster will ‘appear’ to be more responsive to requests even if you aren’t concerned about millisecond response times. Most of you will have already had this drilled into your head over and over: The goal should be fewer and smaller files, using CDNs, moving CSS and JavaScript library loading operations to the bottom of your html pages, use inline images and the list goes on and on. There are many articles on the web about improving performance. Search for ‘website performance’ to find out more. Another example, Steve Souder has an excellent website and even written books on the subject.

Caching. Consider page cache settings carefully. The subject of setting header caches, such as ETags, Expires and Last-Modified headers, is often overlooked and usually misunderstood. Cached content cuts down on the total number of HTTP requests when someone loads your web page. Static content, or content that doesn’t change much, usually has longer cache times than content that changes frequently.  Even though there are many articles on the web about caching, doing it well can be tricky. It can be very handy to hire an expert to figure out optimal configurations in a short period of time. Or in my case, I spent several months of experimenting while subjecting my blog readers to unnecessary page lag, and variety of other problems, until I finally broke down and hired an expert.

HTTP requests that block. Be aware of any HTTP operations that block the loading or use of your pages.  If you have to use a blocking HTTP request then make sure you set a timeout in the client request, such as 20 seconds and display some sort of a loading icon. A good web designer can help walk you through the UI experience. Most modern web servers have server-based timeouts that are longer than most people are willing to wait.

Auto-retry. Alternatively, consider a significantly shorter HTTP timeout setting and retry the connection several times before failing and notifying the user that the app couldn’t connect. These days a single 404 error doesn’t necessarily mean the website is down. But…very, very few websites employ this pattern. So what happens in response is most people reflexively keep hitting reload when there are any loading problems. Reloading an entire page is much more bandwidth intensive on your servers as compared to having the app simply retrying quietly and quickly in the background to load a specific item.

More efficient database polling. Long running database queries can give the impression that the connection is broken. If you have requirements to poll a server-side database for changes, consider implementing a server-based process that simply returns a JSON-based Boolean such as {changes: “false”} if there are no changes. In comparison, most server-side database requests typically run entire and potentially complex SQL queries with every internet request to tell you nothing changed.  From a server resource preservation viewpoint, it’s significantly less overhead to return a simple JSON-based Boolean and let a long-running server side process do all the heavy lifting on a regular timer cycle.

Fail gracefully.  Don’t hang an entire page if your app fails to load a JavaScript library or some other content throws a 404 error, or if a database request fails. Don’t do it. I know this seems obvious, but I see it all the time when doing my daily web surfing. See my suggestions above for handling HTTP requests. Most major companies seem to be guilty of this for activities such as viewing billing pages.  Let the end user know through some sort of a pop-up that a connection has failed or timed out. Native mobile applications have built in mechanisms for doing this, and granted they can auto-detect when the Internet connection goes down, but I still believe regular web apps should mimic the behavior when possible.

ApplicationCache. Consider storing some pages and resources for when a connection goes down by using the HTML5 ApplicationCache interface. This lets you go beyond the typical caching mechanisms using patterns that can be easier to understand and control as compared to the somewhat black box and variable nature of header settings.

Feedback. The ability to email web administrators directly has lost favor over the last five years or so. I suggest bringing this back in a big way, along with clearly posted links. Sometimes the best way to know something is down or slow is to hear it directly and immediately from a customer. Yeh sure, you’ll get some spam email but if it means keeping customers happy then there are both automated and manual ways to deal with it that work. I can speak personally on this topic as my blog has received over 40,000 spam attempts of which I’ve personally deleted over 3,000, and I’m just a team of one. Some techy sites do provide a “Performance” section of their forums, which is fine as long as employees are actually monitoring it (often). The problem with forums is notification of new posts…and, of course, is usually done via email.

Uptime Monitors. Use uptime monitors from different spots around the country you live in, or around the world if you are using a worldwide CDN. Some providers can do this for you, but you should ask questions. The most common scenario I’ve seen is that the update monitor lives in the same server farm as the web server. This is okay but it doesn’t cover the scenario of connectivity outside your firewall. Uptime monitors should not just ping a website, they should also attempt to load and parse actual content, throw a warning email or text message if the content throws an error and throw a warning if a connection takes too long. There are many reasons why you may think your website is up and it’s not. For example, a CDN node could be down, a CDN server could have the wrong permissions, a major Internet router could be down, or your support folks could be using an internal pathway to view pages on your web server that is no longer visible to the outside world. These types of monitors don’t cost much to operate and can significantly boost customer service ratings and help keep customers happy.

Browser Support. Last but not least and probably the touchiest subject is browser support. My recommendation is if you don’t support a particular browser type, then give the end user a message that says some functionality may not work properly. We’ve all been to sites on our tablets or phones, for example, and popups didn’t work right or things didn’t display properly. Non-tech -savvy end users can easily misunderstand these types of things since it rightly gives the appearance that something is broken. If a popup didn’t work it may appear that a sale did not complete, for example. It’s very easy these days to use libraries for browser detection. Doing browser detection should always be part of a web app deployment plan.

Resources

HTTP Caching Protocols (W3C)

What is a CDN?

Beginners Guide to ApplicationCache

Browser support – Caniuse.com