docs: function createClient (ravelInstance, restrict = true) {
    const localRedis = ravelInstance.get('redis port') === undefined || ravelInstance.get('redis host') === undefined;
    ravelInstance.on('post init', () => {
      ravelInstance.$log.info(localRedis
        ? 'Using in-memory key-value store. Please do not scale this app horizontally.'
        : `Using redis at ${ravelInstance.get('redis host')}:${ravelInstance.get('redis port')}`);
    });
    let client;
    if (localRedis) {
      const mock = require('redis-mock');
      mock.removeAllListeners(); // redis-mock doesn't clean up after itself very well.
      client = mock.createClient();
      client.flushall(); // in case this has been required before
    } else {
      client = redis.createClient(
        ravelInstance.get('redis port'),
        ravelInstance.get('redis host'),
        {
          'no_ready_check': true,
          'retry_strategy': retryStrategy(ravelInstance)
        });
    }
    if (ravelInstance.get('redis password')) {
      client.auth(ravelInstance.get('redis password'));
    }
    // log errors
    client.on('error', ravelInstance.$log.error);
  
    // keepalive when not testing
    const redisKeepaliveInterval = setInterval(() => {
      client && client.ping && client.ping();
    }, ravelInstance.get('redis keepalive interval'));
    ravelInstance.once('end', () => {
      clearInterval(redisKeepaliveInterval);
    });
  
    if (restrict) {
      disable(client, 'quit');
      disable(client, 'subscribe');
      disable(client, 'psubscribe');
      disable(client, 'unsubscribe');
      disable(client, 'punsubscribe');
    } else {
      const origQuit = client.quit;
      client.quit = function (...args) {
        clearInterval(redisKeepaliveInterval);
        return origQuit.apply(client, args);
      };
    }
  
    client.clone = function () {
      return createClient(ravelInstance, false);
    };
  
    return client;
  }