Posted on 1 Comment

Prevent Redis client from crashing your Node.js app

Credit: http://crash.rocks/
Credit: http://crash.rocks/

Redis is a high-performance in-memory database that is often used for data caching on server-side. The redis npm package makes is nice & easy to use Redis to cache data in a Node app. If you are new to Redis, you will find this tutorial on Coligo helpful in implementing data caching in your own application. It often results in 10x or more performance increase. Don’t take my work, check it out yourself!

An annoying issue with the redis package is that, if Redis server is not running, doing this emits an uncaught exception, crashing the whole app:

redisClient = redis.createClient();

As this operation, like most operations in Node, is asynchronous, using try-catch simply doesn’t work.

My solution is to create a singleton Redis client instance that handles the Redis-server-not-running case through its retry_strategy option. When Redis server is not running, my singleton returns a fake Redis client that has same function names as the real Redis client. This gives me the benefit of using redis package’s code the way it’s advertised on its documentation without any additional error handling code and without worrying about whether Redis server is running.

I hope my code helps you too. Just create a file redisClient.js somewhere in your Node app and require it when you need to use it.

var redisClient = require('common/redisClient');
 
...
 
var redis = redisClient.getClient();
redis.setex(unique_key_name, 60, data_to_be_cached);

 

/////////////////////////////////////////////////
// Singleton for Redis cache database client.
//
// @file: redisClient.js
// @author: Anurag Bhandari
/////////////////////////////////////////////////
 
var redis = require('redis');
 
var redisClient = (function () {
 
    // Start with a fake client so that we have a client that works
    // even when Redis server is down
    var client = {
        get: function (key, cb) {
            cb(null, null);
        },
        setex: function (key, time, value) {
            // Do nothing in particular
        }
    };
 
    // Attempt to create a new instance of an actual redis client
    var connectionString = process.env.REDIS_URL || 'redis://localhost:6379';
    var c = redis.createClient(connectionString, {
        retry_strategy: function (options) {
            if (options.error.code === 'ECONNREFUSED') {
                // This will suppress the ECONNREFUSED unhandled exception
                // that results in app crash
                return;
            }
        }
    });
 
    // Set the "client" variable to the actual redis client instance
    // once a connection is established with the Redis server
    c.on('ready', function () {
        client = c;
    });
 
    /**
     * Get a redis client
     * @return {Object} client - eventually a proper redis client object (if redis is up) or a fake client object (if redis is down)
     */
    var getClient = function () {
        return client;
    };
 
    return {
        getClient: getClient
    }
 
})();
 
module.exports = redisClient;
Posted on Leave a comment

Running opentaps in Windows

So I’m playing around with opentaps these days. It runs pretty neatly in Linux. Simply executing a shell script it comes with autostarts a built-in Tomcat server and runs the darn thing without a hitch. opentaps under Windows is another animal!

Although opentaps comes with a similar batch script for Windows, the thing doesn’t run without errors. With JDK and all set all right, I was getting this error when visiting opentaps in browser:

HTTP Status 500 –

type Exception report

message

description The server encountered an internal error () that prevented it from fulfilling this request.

exception

java.util.regex.PatternSyntaxException: Unexpected internal error near index 1
\
^
java.util.regex.Pattern.error(Pattern.java:1713)
java.util.regex.Pattern.compile(Pattern.java:1466)
java.util.regex.Pattern.(Pattern.java:1133)
java.util.regex.Pattern.compile(Pattern.java:823)
java.lang.String.split(String.java:2293)
java.lang.String.split(String.java:2335)
org.ofbiz.webapp.control.ConfigXMLReader.injectControllerIfNeeded(ConfigXMLReader.java:81)
org.ofbiz.webapp.control.ConfigXMLReader.getControllerConfig(ConfigXMLReader.java:133)
org.ofbiz.webapp.control.ConfigXMLReader$ControllerConfig.loadIncludes(ConfigXMLReader.java:351)
org.ofbiz.webapp.control.ConfigXMLReader$ControllerConfig.(ConfigXMLReader.java:170)
org.ofbiz.webapp.control.ConfigXMLReader.getControllerConfig(ConfigXMLReader.java:132)
org.ofbiz.webapp.control.ConfigXMLReader$ControllerConfig.loadIncludes(ConfigXMLReader.java:351)
org.ofbiz.webapp.control.ConfigXMLReader$ControllerConfig.(ConfigXMLReader.java:170)
org.ofbiz.webapp.control.ConfigXMLReader.getControllerConfig(ConfigXMLReader.java:132)
org.ofbiz.webapp.control.RequestHandler.getControllerConfig(RequestHandler.java:97)
org.ofbiz.webapp.control.RequestHandler.getDefaultErrorPage(RequestHandler.java:647)
org.ofbiz.webapp.control.ControlServlet.doGet(ControlServlet.java:239)
javax.servlet.http.HttpServlet.service(HttpServlet.java:617)
javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
org.ofbiz.webapp.control.ContextFilter.doFilter(ContextFilter.java:270)

note The full stack trace of the root cause is available in the Apache Tomcat/6.0.26 logs.
Apache Tomcat/6.0.26

It’s amazing that a simple hack posted by someone in 2011 worked for me! After modifying ConfigXMLReader.java as mentioned in the forum post, be sure to recompile opentaps by running the ant command. Don’t have ant installed? Read this.

Posted on Leave a comment

Sencha Touch: Third-party plugins and build errors

Nothing beats Sencha Touch when it comes to sheer number of options and versatility in developing for the mobile. ST has truly set the benchmark of mobile development done right with each major release. It has a vibrant user community, and a robust enterprise adoption. But, sadly, although the documentation is good, it sometimes feels a bit incomplete. If it weren’t for stackoverflow and ST’s official forums, it would have been difficult for me to complete some aspects of my recent mobile app project. Coming to the point…

ST recently announced the much awaited grid feature . They call it Touch Grid. On the surface, it looks super-customizable (just like everything else ST) and enterprise-ready. In short, it’s just what everyone was waiting for. Unfortunately, it is not available for free. Touch Grid comes as part of the Sencha Touch Bundle, something only suited to the enterprise due to its staggering $695 cost.

A couple of months ago, I was looking for something like Touch Grid for my app. The exorbitant pricing of ST Bundle compelled me to look for free alternatives. That was when I found Ext.ux.touch.grid. Its last release was well over a year ago now, and was tested with ST 2.2. But it still works with ST 2.3 (the current release). Including its source folder “Ext.ux.touch.grid” in the root of my ST app and adding a reference to it in my app.js was all that was needed to get it to work.

When I built my app for production deployment (sencha app build production), I got this error:

Unknown definition for dependency: Ext.ux.touch.grid

The above error basically pops up because of not adding a dependency (say, a plugin) in your ST app’s classpath. Adding it to the classpath resulted in the yet another error:

com.sencha.exceptions.ExBuild: java.lang.IllegalArgumentException

A small tweak fixed this error: I created a new folder “plugins” in the root of my app and moved the “Ext.ux.touch.grid” folder into it. I edited my app.js to change the plugin’s path, and likewise changed the classpath.

Add this to the top of app.js (before Ext.application declaration):

Ext.Loader.setConfig({
    enabled: true,
    paths: {
        'Ext.ux.touch.grid': './plugins/Ext.ux.touch.grid'
    }
});

And add the “plugins” folder to the app’s classpath (edit .sencha/app/sencha.cfg):

app.classpath=${app.dir}/app.js,${app.dir}/app,${app.dir}/plugins

Now build again, and all should be fine!
Happy coding.