Ejemplo n.º 1
0
Manager.prototype.createClient = function () {
    var self = this;
    var host = this.options.host || 'localhost';
    var port = this.options.port || 6379;
    var options = this.options.options || {};
    check(port).isInt();

    var client = new redis.createClient(port, host, options);
    if (typeof options.auth == 'string') {
        client.auth(options.auth);
    }
    client.on('error', function (err) {
        console.log('[' + self.id + '] ' + err);
    });
    client.on('ready', function () {
        console.log('[' + self.id + '] connected to redis!');
        self.emit('ready');
        self.retried = 0;
    });
    client.on('end', function () {
        self.emit('end');
        console.log('[' + self.id + '] disconnected from redis');
    });
    return client;
};
Ejemplo n.º 2
0
IpcRedisClient.prototype.initClient = function(name, host, port)
{
    var opts = this.options[name] || this.options;
    host = String(host).split(":");
    // For reconnect or failover to work need retry policy
    if (opts.servers.length > 1 || this.sentinel) {
        var connect_timeout = lib.toNumber(opts.connect_timeout, { min: 60000, dflt: 86400000 });
        var retry_max_delay = lib.toNumber(opts.retry_max_delay, { min: 100, dflt: 60000 });
        var max_attempts = lib.toNumber(opts.max_attempts, { min: 1, dflt: 10 });
        var self = this;
        opts.retry_strategy = function(options) {
            logger.dev("initClient:", options);
            if (options.total_retry_time > connect_timeout || (lib.isArray(opts.servers) && options.attempt > max_attempts)) {
                setTimeout(self.onError.bind(self, self.name, { code: 'CONNECTION_BROKEN', message: opts.error && opts.error.message }), 100);
                return undefined;
            }
            return Math.min(100, Math.min((options.attempt % max_attempts) * 200, retry_max_delay));
        }
    }
    var Redis = require("redis");
    var client = new Redis.createClient(host[1] || port || opts.port || 6379, host[0] || "127.0.0.1", opts);
    client.on("error", this.onError.bind(this, name));

    switch (name) {
    case "sentinel":
        client.on('pmessage', this.onSentinelMessage.bind(this));
        client.on("ready", this.onSentinelConnect.bind(this));
        break;

    default:
        client.on("ready", this.emit.bind(this, "ready"));
        client.on("message", this.onMessage.bind(this, name));
        client.on("connect", this.onConnect.bind(this, name));
    }

    if (this[name]) this[name].end(true);
    this[name] = client;
    logger.debug("initClient:", name, this.url, "connecting:", host, port);
}
/*
options includes:
- host
- port
- masterOptions
- masterName
- logger (e.g. winston)
- debug (boolean)
*/
function RedisSentinelClient(options) {

  // RedisClient takes (stream,options). we don't want stream, make sure only one.
  if (arguments.length > 1) {
    throw new Error("Sentinel client takes only options to initialize");
  }

  // make this an EventEmitter (also below)
  events.EventEmitter.call(this);

  var self = this;

  this.options = options = options || {};

  this.options.masterName = this.options.masterName || 'mymaster';

  self.emitMasterErrors = false;

  // no socket support for now (b/c need multiple connections).
  if (options.port == null || options.host == null) {
    throw new Error("Sentinel client needs a host and port");
  }


  // if debugging is enabled for sentinel client, enable master client's too.
  // (standard client just uses console.log, not the 'logger' passed here.)
  if (options.debug) {
    RedisSingleClient.debug_mode = true;
  }

  var masterOptions = options.masterOptions || {};
  masterOptions.disable_flush = true; // Disables flush_and_error, to preserve queue

  // if master & slaves need a password to authenticate,
  // pass it in as 'master_auth_pass'.
  // (corresponds w/ 'auth_pass' for normal client,
  // but differentiating b/c we're not authenticating to the *sentinel*, rather to the master/slaves.)
  // by setting it to 'auth_pass' on master client, it should authenticate to the master (& slaves on failover).
  // note, sentinel daemon's conf needs to know this same password too/separately.
  masterOptions.auth_pass = options.master_auth_pass || null;

  // this client will always be connected to the active master.
  // using 9999 as initial; expected to fail; is replaced & re-connected to real port later.
  self.activeMasterClient = new RedisSingleClient.createClient(9999, '127.0.0.1', masterOptions);

  
  // pass up errors
  // @todo emit a separate 'master error' event?
  self.activeMasterClient.on('error', function(error){
    if (self.emitMasterErrors) {
      error.message = self.myName + " master error: " + error.message;
      self.onError.call(self, error);
    }
  });

  // pass up messages
  self.activeMasterClient.on('message', function(channel, message){
    self.emit('message', channel, message);
  });

  // pass up pmessage
  self.activeMasterClient.on('pmessage', function(pattern, channel, message){
    self.emit('pmessage', pattern, channel, message);
  });

  // pass these through
  ['unsubscribe','end', 'reconnecting'].forEach(function(staticProp){
    // @todo rewrite this to use `apply`
    self.activeMasterClient.on(staticProp, function(a, b, c, d){
      self.emit(staticProp, a, b, c, d);
    });
  });


  // used for logging & errors
  this.myName = 'sentinel-' + this.options.host + ':' + this.options.port + '-' + this.options.masterName;


  /*
  what a failover looks like:
  - master fires ECONNREFUSED errors a few times
  - sentinel listener gets:
    +sdown
    +odown
    +failover-triggered
    +failover-state-wait-start
    +failover-state-select-slave
    +selected-slave
    +failover-state-send-slaveof-noone
    +failover-state-wait-promotion
    +promoted-slave
    +failover-state-reconf-slaves
    +slave-reconf-sent
    +slave-reconf-inprog
    +slave-reconf-done
    +failover-end
    +switch-master

  (see docs @ http://redis.io/topics/sentinel)

  note, these messages don't specify WHICH master is down.
  so if a sentinel is listening to multiple masters, and we have a RedisSentinelClient
  for each sentinel:master relationship, every client will be notified of every master's failovers.
  But that's fine, b/c reconnect() checks if it actually changed, and does nothing if not.
  */

  // one client to query ('talker'), one client to subscribe ('listener').
  // these are standard redis clients.
  // talker is used by reconnect() below
  this.sentinelTalker = new RedisSingleClient.createClient(options.port, options.host);
  this.sentinelTalker.on('connect', function(){
    self.debug('connected to sentinel talker');
  });
  this.sentinelTalker.on('error', function(error){
    error.message = self.myName + " talker error: " + error.message;
    self.onError.call(self, error);
  });
  this.sentinelTalker.on('end', function(){
    self.debug('sentinel talker disconnected');
    // @todo emit something?
    // @todo does it automatically reconnect? (supposed to)
  });

  var sentinelListener = new RedisSingleClient.createClient(options.port, options.host);
  sentinelListener.on('connect', function(){
    self.debug('connected to sentinel listener');
  });
  sentinelListener.on('error', function(error){
    error.message = self.myName + " listener error: " + error.message;
    self.onError(error);
  });
  sentinelListener.on('end', function(){
    self.debug('sentinel listener disconnected');
    // @todo emit something?
  });

  // Connect on load
  this.reconnect();

  // Subscribe to all messages
  sentinelListener.psubscribe('*');

  sentinelListener.on('pmessage', function(channel, msg) {
    self.debug('sentinel message', msg);

    // pass up, in case app wants to respond
    self.emit('sentinel message', msg);

    switch(msg) {
      case '+sdown':
        self.debug('Down detected');
        self.emit('down-start');
        self.emitMasterErrors = false;
        break;

      case '+failover-triggered':
        self.debug('Failover detected');
        self.emit('failover-start');
        break;

      case '+switch-master':
        self.debug('Reconnect triggered by ' + msg);
        self.emit('failover-end');
        self.reconnect();
        break;
    }
  });

}
Ejemplo n.º 4
0
'use strict';

var express = require('express'),
    router = express.Router(),
    redis = require('redis'),
    menu = require('../menu'),
    debug = require('debug')('app:awesome'),
    os = require("os");

var port = process.env.REDIS_PORT || 6379;
var host = process.env.REDIS_HOST || 'localhost';
var redisCache = new redis.createClient(port,host, {'max_attempts':3});
redisCache.on("error", function (err) {
        console.error("Awesome v2 Error " + err);
        redisCache = null;
    });
router.get('/', function(req, res) {
    var data = {
        menu: menu('awesome_v2'),
        layout: "template"
        };

    res.render('awesome_v2',data);

});

router.get('/app', function(req, res) {
    var data = {
        layout: "template_app",
        hostname: os.hostname()
        };