Configure Caching for a Model

What you’ll build

While following this guide, you will start an oeCloud Framework based NodeJS application and -

  • create a new Model called Product
  • configure the new model for caching

What you’ll need

To complete this guide, you will need the following -

  • an understanding of what a Model is in the context of Loopback, which is the basis of the oeCloud Framework. You can get this by perusing the documentation here
  • a running NodeJS application built using the oeCloud Framework. You can get this here
  • a working REST client. You can use the Linux cURL command as a REST client if you have access to a Linux machine or have Git Bash installed on your Windows machine. REST addons for browsers, like Postman for Firefox or Google Chrome also can be used to complete this guide.
  • a text editor for editing a configuration file

Cache Mechanism

The cache mechanism will be updated at get, update and delete operations. The oeCloud Framework uses two types of cache:

  1. Instance Cache
  2. Query Cache

When enabled, Instance Cache of a model consists all non-empty results for queries on a primary key of that model. When enabled, Query Cache of a model consists all results (empty and non-empty) of all other queries on that model.

Instance Cache

Enabling Instance Cache

Instance cache is not enabled by default, for a Model in a NodeJS application using the oeCloud Framework. In order to enable it, we use the following fields in the options field:

  • disableInstanceCache - indicator to enable\disable Instance Cache. If it is set to false, the Instance cache is enabled. By default, set to true.
  • disableManualPersonalization - indicator to enable\disable manual personlization. In order to use instache cache, manual personalization must be switched off. Meaning the field should be set to true.

For example, create the Product model with the following definition:

{
    "name": "Product",
    "base": "BaseEntity",
    "strict": false,
    "plural": "Products",
    "idInjection": true,
    "options": {
        "disableInstanceCache": false,
        "disableManualPersonalization": true
    },
    "properties": {
        "name": {
            "type": "string"
        }
    }
}

Instance Cache Configuration

Instance cache can be configured per model. In order to configure the cache, we use the following 2 fields in the options field:

  • instanceCacheSize - The Insatcne Cache size, default is 10000.
  • instanceCacheExpiration - Instance Cache entries ttl, the default is 0. 0 is no expiration time.

For example, create the Product model with the following definition:

{
    "name": "Product",
    "base": "BaseEntity",
    "strict": false,
    "plural": "Products",
    "idInjection": true,
    "options": {
        "disableManualPersonalization": true,
        "disableInstanceCache": false
        "InstanceCacheSize" : 1000,
        "InstanceCacheExpiration": 50000
    },
    "properties": {
        "name": {
            "type": "string"
        }
    }
}

Skip Instance Cache Option

Sometimes, when you are performing a critical request, you want to get the most updated data from the DB, and not from the cache. You can do it by setting the following field on your request’s options (or in a query string in your request url if you are using REST API):

  • noInstanceCache - when set to true in a request’s context, and when the query is such that it’s result should be kept in Instance Cache, the request will go directly to DB for fetching data, and will update the Insatance Cache with the fetched value. In REST API the query string’s value should be 1.

For example, a programmatic request will look like:

    var ctx = <SOME_CTX>;
    var loopback = require('loopback');
    var Product = loopback.getModel('Product', ctx);
    ctx.noInstanceCache = true;
    Product.find({ "where": { "id": <SOME_ID> } }, ctx, function (err, data) {
        if (err) {
            return console.log(err);
        }
        return;
    });

For example, a REST request will look like:

    var request = require('request');
    var baseSchedulerUrl = 'https://' + appHost + '/api/';
    var token = <SOME_TOKEN>
    request.get(
        baseSchedulerUrl + 'Products?filter={"where":{"id": "' + 123 + '"}}&noInstanceCache=1&access_token=' + token,
        {json: {}},
        function (error, response, body) {
            if (error || body.error) {
                return console.log('error:', error || body.error);
            }
            return;
        }
    );

Disclaimer

  • Instance cache is disabled for all models if CONSISTENT_HASH environment variable is not set to true.

Query Cache

Caching can be enabled for a Model in a NodeJS application using the oeCloudFramework in one of two ways.

  • Method 1: Marking the Model to be cacheable within the definition of the Model.
  • Method 2: Marking the Model to be cacheable in a configuration file.

Method 1: Marking the Model to be cacheable within the definition of the Model

This is done at Model creation time. While creating the model, add the property

cacheable: true

to the Model definition JSON.

For example, create the Product model with the following definition:

{
    "name": "Product",
    "base": "BaseEntity",
    "strict": false,
    "plural": "Products",
    "idInjection": true,
    "options": {
        "cacheable": true
    },
    "properties": {
        "code": {
            "type": "string"
        },
        "name": {
            "type": "string"
        },
        "category": {
            "type": "string"
        }
    }
}

Do the following to create the above cached Model:

  • Open a command window (“cmd” in Windows OS, “bash” Terminal in Linux)
  • copy the following command to the command prompt, change the host and port, if necessary, and hit the ENTER key:

curl -v “http://localhost:3000/api/ModelDefinitions” -H “Content-Type: application/json” -H “Accept: application/json” –data “{"cacheable": true, "name": "Product","base": "BaseEntity","strict": false,"plural": "Products","idInjection": true,"options": {"validateUpsert": true},"properties": {"code": {"type": "string"},"name": {"type": "string"},"category": {"type": "string"},"price": {"type": "number"},"offeredSince": {"type": "date"},"active": {"type": "boolean"},"description": {"type": "string"}}}”

This creates the Product Model as a cacheable Model.

Method 2: Marking the Model to be cacheable in a configuration file

In case a model was not marked as cacheable at the time of creating it as described above, the model can still be made cacheable by editing a configuration file. The file to be edited is server/config.json

To use this feature, do the following:

  • edit the server/config.json file with a text editor and add the following entry to it:
"modelstocache": ["Product"]
  • restart the (node) application

This will enable caching for the Product model.

Note: Caching can be disabled globally for all Models irrespective of whether they are marked as cacheable. This is achieved by adding a property

"disablecaching": true

to the server/config.json file. By default, the disablecaching property is absent from the config file and hence its value is treated as false, thereby allowing any Model to be cached if marked cacheable by either of the two methods described above.

Query Cache Configuration

Query cache can be configured per model. In order to configure the cache, we use the following 2 fields in the options field:

  • queryCacheSize - The Query Cache size, default is 10000.
  • queryCacheExpiration - Query Cache entries ttl, the default is 1000. The Query cache should be relatively short.

For example, create the Product model with the following definition:

{
    "name": "Product",
    "base": "BaseEntity",
    "strict": false,
    "plural": "Products",
    "idInjection": true,
    "options": {
        "queryCacheSize" : 5000,
        "queryCacheExpiration": 700
    },
    "properties": {
        "name": {
            "type": "string"
        }
    }
}

Skip Query Cache Option

Sometimes, when you are performing a critical request, you want to get the most updated data from the DB, and not from the cache. You can do it by setting the following field on your request’s options (or in a query string in your request url if you are using REST API):

  • noQueryCache - when set to true in a request’s context, and when the query is such that it’s result should be kept in Query Cache, the request will go directly to DB for fetching data, and will update the Query Cache with the fetched value. In REST API the query string’s value should be 1.

For example, a programmatic request will look like:

    var ctx = <SOME_CTX>;
    var loopback = require('loopback');
    var Product = loopback.getModel('Product', ctx);
    ctx.noQueryCache = true;
    Product.find({ "where": { "name": <SOME_NAME> } }, ctx, function (err, data) {
        if (err) {
            return console.log(err);
        }
        return;
    });

For example, a REST request will look like:

    var request = require('request');
    var baseSchedulerUrl = 'https://' + appHost + '/api/';
    var token = <SOME_TOKEN>
    request.get(
        baseSchedulerUrl + 'Products?filter={"where":{"name": "' + <SOME_NAME> + '"}}&noQueryCache=1&access_token=' + token,
        {json: {}},
        function (error, response, body) {
            if (error || body.error) {
                return console.log('error:', error || body.error);
            }
            return;
        }
    );

Summary

We have seen two different model cache mechanism.

  • Instance Cache
  • Query Cache

We have seen how we can configure Instance Cache for a model. We also saw how we can enable Query cache for a Model in the oeCloudFramework based NodeJS application in two different ways.