Project

General

Profile

Usage

This plugin utilizes the Jedis library for interfacing to the Redis server. Connections are made directly to the server rather than in a connection pool, because of this you should not try using your connection object in another thread and instead instantiate a new connection. This lack of thread safety won't pose an issue to 99% of all servoy projects as the clients run in a single thread, however I wanted to make it stated incase someone is doing something really unique.

A warning


There are only two hard things in Computer Science: cache invalidation and naming things.
-- Phil Karlton

Caching data is not a panacea to all speed problems. If you don't fully grasp the lifecycle of the data your application produces adding a caching layer could cause behaviors that you will pull your hair out trying to track down. Start small and get a feel for how it all works.

Connecting to the server

Currently all connections are made to the default database '0' without authentication.

 //you can additionally pass a port parameter if you server isn't running on the default port of 6379
var client = plugins.Redis.createRedisClient('localhost'); 
if (client.isConnected() == true) {
    application.output("Made a connection to the Redis server");
} else {
    application.output("Connection to Redis server failed");
}

Creating and retrieving keys

Currently supported are keys with a string key name and a string value. If key already holds a value, it is overwritten, regardless of its type. Any previous TTL associated with the key is discarded on successful .set() operation. Keys can be assigned an expire time that begins counting down at the moment that they are saved, when they reach 0 the key is removed from the database.

var client = plugins.Redis.createRedisClient('localhost');
//creating a basic key
var set_result = client.set("someKey", "foo");
application.output("Result of client.set(): "+set_result);  // true

//getting the value of the key we just created
var get_result = client.get("someKey");
application.output("Result of client.get(): "+get_result);  // "foo" 

//overwriting a key with a new value
var second_set_result = client.set("someKey", "bar");
application.output("Result of client.set(): "+second_set_result);  // true

//getting the value of the key we just updated
var second_get_result = client.get("someKey");
application.output("Result of client.get(): "+second_get_result);  // "bar" 

//creating a key that expires
var expiring_key_result = client.set("expiringKey", "Soon I'll be gone...", 3); // 3 second TTL
application.output("Result of client.set() with TTL: "+expiring_key_result);  // true

if (client.exists("expiringKey") == true) {
  application.output("expiringKey is still here, and it should be for a few more seconds");
}

application.sleep(5000);  //sleep for 5 seconds

if (client.exists("expiringKey") == false) {
  application.output("expiringKey is gone now");
}

Creating keys that store single string values is useful enough by itself, but lets take it to the next level and store a more complex object in the Redis server. Any data that you can serialize into a JSON string can then be stored in the server. In this example we are taking a function that displays some sales data on a dashboard, but the underlying SQL query is very slow and is causing a poor user experience. Since the data displayed on the dashboard doesn't really need to be accurate up to the second the user requests the page, we will cache the values of when it first runs for a period of time so that subsequent requests from the same or other clients will get the cached version back instantly. The cached values expire after 30 minutes, at which point the next request will refresh the values cached in the database. I'll leave the idea of having a background process update the cache as an exercise for you.

Note that this code uses the excellent Velocity Report plugin for its JSON serialization.

function loadDashboard() {

  /*
  * This function take forever to run, one day I will figure out why.
  */
  function getTotalSales() {
    var result = [];
    var dash_data;
    var json_dash_data;

    var very_long_running_sql_query = "SELECT customer_id, COUNT(*) as `number of sales`, SUM(sales) as `total` FROM sales GROUP BY customer_id";
    var sales_ds = databaseManager.getDataSetByQuery("localhost", very_long_running_sql_query, [], -1);
    for (var i=1;i<=sales_ds.getMaxRowIndex(); i++) {
      var row = sales_ds.getRowAsArray();
      result.push(row);
    }
    return result;
  }

 var client = plugins.Redis.createRedisClient('localhost');
 if (client.exists("totalSales")) {
   //it was in the cache, lets use it
   json_dash_data = client.get("totalSales");
   dash_data = plugins.VelocityReport.fromJSON(json_dash_data, true);
 } else {
   //looks like it was not in the cache, perhaps the old key expired or maybe this is the first call
   //lets save the values we get so future requests can hit the cache
   dash_data = getTotalSales();
   json_dash_data = plugins.VelocityReport.toJSON(dash_data, true); 
   client.set("totalSales", json_dash_data, 1800)   //cache it for 30 minutes
 }

  return dash_data;
}