RapCache - A ServiceNow Key-Value Pair Cache

January 13, 2022
|
5
min read

If you have been around ServiceNow for a while, you know with a large degree of confidence that ServiceNow is a Relational Database with a sexy GUI. Toss in a workflow engine, some eventing, sprinkle in a few other goodies, and “presto!” you can make work do a little flow for you here and there. 

ServiceNow is really good at taking instruction from a single place and executing it in another single place while enabling people to poke at the work as it goes from point A to point B. That instruction may come from a Script Include or it may come from a server in Grandma’s secret lair (trust me, she has one). What ServiceNow did not intend to be is a high-performing developer-friendly key-value store. But, if it could be, why would we want it to be?

As a Developer or Engineer, your solution is always limited to the tools you have available and in ServiceNow, there are already many ways to get the job done. The same holds true when I start a home improvement project and I consider the tools I have in my garage. Even though I already have them, it doesn’t stop me from walking around Home Depot thinking of all the new projects I could start with all the tools on display. In that same way I wonder what I can build while perusing AWS services. Safe to say, Home Depot purchases were made and now I am a better handyman for it and my wife loves me more for it. See the pattern? Robert California agrees.

So what on Earth did I do?

I created the RapCache App. A very simple app that you install in your ServiceNow platform to play with. It will sit there for a bit until a problem appears in your workshop that needs resolving and it will hit you. “Holy smokes! I installed an app a couple of weeks ago that will efficiently enable me to effectively do that thing you want, Boss!”. And they will love you more for it. See the pattern?

“But why do we need a new tool?”

A standardized key-value store and caching mechanism is great for several reasons:

  1. Your app needs to quickly access unstructured data many times. Pop the data into memory and commit it to disk only when you need to.
  2. You are orchestrating tasks from a main script across available nodes and you need to transfer data between the workers and/or back to the main script.
  3. You have an asynchronous event driven architecture and you want to easily share data between various transactions running at very different times.
  4. Some components of your app are simple, they don’t require structured data and don’t require long term persistent storage.
  5. You want to seamlessly communicate with processes running in memory on the server side, from processes running in memory on the client side.
  6. And many more reasons…

So here is to the new hammer in your tool belt; let’s rock and roll!

Install:

Go install the app on your instance then come back for some fun (You’ll see the update set in the repo):

https://github.com/rapdev-io/servicenow-oss/tree/main/rapcache

Overview:

The RapCache App consists of the following important objects:  

1) Cache Table and a Key Value Pair Column

2) Script Include

3) Scripted Rest Service with resources

4) A safety mechanism to delete old caches because... Developers

Create a Cache  

In ServiceNow:

var c = new RapCache().init();
/* then check your table for the cache */


 In Python

import requests
url = 'https://{instance-name}.service-now.com/api/x_266114_rap_cache/v1/init'
response = requests.post(url, auth=('user', 'pwd'), headers={"Content-Type":"application/json","Accept":"application/json"})
print(response.text)

Setting Key-Value Pairs

/* 
Using the cache you just created - go grab the sys_id 
You don’t always need to set() the cache. As RapCache() is constructed the initialized cache is set()
The set() is for when you know a cache is already there
*/
var c = new RapCache();
c.set('bb6ad16e2fb80110a972a55df699b69d'); //sets the current cache
c.edit('boom','{"bestShow":"GameOfThrones"}');

Now we can go retrieve that value with this

gs.info(c.get('boom'));
/* or if you think a different show is better... */
var kv = c.get('boom');
var obj = JSON.parse(kv);
obj["best_show"] = "Breaking Bad";
/* then commit your statement to disk */
c.edit('boom',JSON.stringify(obj));

It’s convenient to throw many kv pairs into a single referrable cache

/* lets add a couple more */
var c = new RapCache();
c.set('bb6ad16e2fb80110a972a55df699b69d'); //sets the current cache
c.edit('shakalaka','{"bestMovie":"The Departed"}');
c.edit('chikadabang','{"bestSong":"Roar"}');
/* Then we can get all the kv Pairs with this */
var pairs = c.getAll();
gs.info(pairs);

/* Then do things with the values*/
for(var key in pairs) {
    gs.info(key + " = " + pairs[key]);
}

Cleaning things up

var c = new RapCache();
c.set('bb6ad16e2fb80110a972a55df699b69d');
c.clear();

Performance

It takes less than 20 seconds to fumble around with 1000 of these.  

Since, by design we are not searching by key, and ever only searching by sys_id of a cache then there is no table scanning of the key value pairs. Any searching/looping/handling of keys and their values would be done by your logic in memory.

var i = 0;
var c = new RapCache();
while( i < 1000){
  i++
  c.init();
  c.edit('boom','{"prop1":"val1"}');
}

If you can’t make up your mind about which show is best, it improves performance by 5x making modifications in memory and waiting to commit modifications to the table until the end. And of course with a larger table, performance gains will be much more (remember that time you tried to query an incident table with millions of records in it?).

var i = 0;
var c = new RapCache();
c.set('b907752a2fbc0110a972a55df699b606');
while( i < 1000){
  i++
  c.cache.pairs['boom'] = '{"bestShow":"GameOfThrones"}';
  c.cache.pairs['boom'] = '{"bestShow":"Breaking Bad"}';
}
c.commit();

So there you have it. A standardized, convenient and efficient way to operate with unstructured data in memory while still getting the benefits of a persistent data store within ServiceNow. 

RapCache by RapDev.

*disclaimer - I’ve provided background scripts, everyone is having fun until you take out a production server. And remember to use your own sys_ids ;)

What’s next?

I would really like to see a python module and a node package with some convenient methods to tap into your ServiceNow’s new key-value store. Who knows, I might just build them soon.

But I would also be interested to see a simple-to-use client side script enabling devs to tap into the server side cache. With UI scripts being a ‘scoped app whoopsie daisy’, I’ll need a couple more beers to think this one through to conserve your precious keystrokes.

written by
Kyle Brueckner
Kyle Brueckner
NC based Technologist with 10 years of ServiceNow experience. Well versed across ITSM, ITOM, ITBM, SecOps, IRM.
Back to main Blog