microlinkhq / keyvhq

Simple key-value storage with support for multiple backends.

Home Page:https://keyvhq.js.org

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Handling connection errors - redis

skinofstars opened this issue · comments

Hi, I'm having trouble figuring out how to add handle connection errors. This is with a view to having a fallback when there is a connection error.

I'm trying somehting along the lines of this

let hasStore;

const store = new KeyvRedis(options.redisUri);
store.on('connect', () => (hasStore = true));
store.on('error', () => (hasStore = false));

But all I'm getting is the following, before I get a chance to do anything with hasStore

      throw er; // Unhandled 'error' event
      ^

Error: connect ECONNREFUSED 127.0.0.1:6379

Any guidance appreciated

Hello, check redis/ioredis#1241 🙂

Ok, I think I'd written my problem wrong, or gone too far down the wrong solution route.

When you use IORedis directly, if the connection fails then you can use a try/catch block. With this module, an error event is emitted. How can I handle a failed connection?

Here is a code example, which when a Redis instance is unreachable, with IORedis it falls back to the database conection.

import Keyv from '@keyvhq/core';
import KeyvRedis from '@keyvhq/redis';
import {debug} from '../handlers/util.debug.js';
import Redis from 'ioredis';

/**
 * Add .cache() to any knex query to make is cachable
 */
export function cacheable(
  knex,
  options = {redisUri: 'redis://localhost:6379', namespace: 'cache'}
) {
  /** Using Keyv */
  // const keyv = new Keyv({
  //   store: new KeyvRedis(options.redisUri),
  //   namespace: options.namespace,
  // });

  /** Using IORedis */
  const redis = new Redis(options.redisUri, {
    keyPrefix: `${options.namespace}:`,
  });

  // https://github.com/knex/knex/issues/2787#issuecomment-530780656=
  knex.QueryBuilder.extend('cache', async function () {
    try {
      const cacheKey = this.toString();

      debug('Cache key: ' + JSON.stringify(cacheKey));

      // const cacheVal = await keyv.get(cacheKey);
      const cacheVal = await redis.get(cacheKey).then((res) => JSON.parse(res));

      if (cacheVal) {
        return cacheVal;
      }

      const data = await this;

      // await keyv.set(cacheKey, data);
      await redis.set(cacheKey, JSON.stringify(data));

      return data;
    } catch (e) {
      debug(e);
      return this;
    }
  });

  return knex;
}

However, using the Keyv library (as commented out in the above code sample), but with an unreachable Redis server, we get the following

node:events:505
      throw er; // Unhandled 'error' event
      ^

Error: connect ECONNREFUSED 127.0.0.1:6379
    at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1187:16)
Emitted 'error' event on Keyv instance at:
    at KeyvRedis.<anonymous> (/Volumes/projects/whotargetsme/wtm-rawlog-parser/node_modules/@keyvhq/core/src/index.js:20:44)
    at KeyvRedis.emit (node:events:527:28)
    at KeyvRedis.emit (node:domain:475:12)
    at EventEmitter.<anonymous> (/Volumes/projects/whotargetsme/wtm-rawlog-parser/node_modules/@keyvhq/redis/src/index.js:26:14)
    at EventEmitter.emit (node:events:527:28)
    at EventEmitter.emit (node:domain:475:12)
    at EventEmitter.silentEmit (/Volumes/projects/whotargetsme/wtm-rawlog-parser/node_modules/ioredis/built/Redis.js:447:30)
    at Socket.<anonymous> (/Volumes/projects/whotargetsme/wtm-rawlog-parser/node_modules/ioredis/built/redis/event_handler.js:189:14)
    at Object.onceWrapper (node:events:642:26)
    at Socket.emit (node:events:539:35) {
  errno: -61,
  code: 'ECONNREFUSED',
  syscall: 'connect',
  address: '127.0.0.1',
  port: 6379
}