Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sentinel: If you subscribe after connection established, you error. #255

Closed
evantahler opened this issue Feb 18, 2016 · 9 comments
Closed

Comments

@evantahler
Copy link

Consider the folowing:

var Redis = require('ioredis');

var config = {
  options: {
    name: 'mymsater',
    db: 10,
    sentinels: [
      { host: '127.0.0.1', port: 26379 },
    ]
  }
};

var pub = Redis.createClient(null, null, config.options);
var sub = Redis.createClient(null, null, config.options);

pub.on('error', function(err){ console.log(err); });
sub.on('error', function(err){ console.log(err); });

pub.on('connect', function(){
  console.log('PUB connected');
});

sub.on('connect', function(){
  console.log('SUB connected');

  sub.subscribe('channel', function(error){
    if(error){ console.log(error); }

    sub.on('message', function(channel, message){
      console.log('[%s]: %s', channel, message);
    })

    pub.publish('channel', 'hello');
  })
});

If you wait until after the connection even to subscribe the following uncaught promise rejection is fired:

Unhandled rejection Error: Connection in subscriber mode, only subscriber commands may be used
    at Redis.sendCommand (/Users/evantahler/Dropbox/Projects/actionhero/node_modules/ioredis/lib/redis.js:500:20)
    at Redis.selectBuffer (/Users/evantahler/Dropbox/Projects/actionhero/node_modules/ioredis/lib/commander.js:117:17)
    at /Users/evantahler/Dropbox/Projects/actionhero/node_modules/ioredis/lib/redis/event_handler.js:184:12
    at /Users/evantahler/Dropbox/Projects/actionhero/node_modules/ioredis/lib/redis/event_handler.js:35:39
    at /Users/evantahler/Dropbox/Projects/actionhero/node_modules/ioredis/lib/redis.js:392:7
    at tryCatcher (/Users/evantahler/Dropbox/Projects/actionhero/node_modules/ioredis/node_modules/bluebird/js/main/util.js:26:23)
    at Promise.successAdapter (/Users/evantahler/Dropbox/Projects/actionhero/node_modules/ioredis/node_modules/bluebird/js/main/nodeify.js:23:30)
    at Promise._settlePromiseAt (/Users/evantahler/Dropbox/Projects/actionhero/node_modules/ioredis/node_modules/bluebird/js/main/promise.js:579:21)
    at Promise._settlePromises (/Users/evantahler/Dropbox/Projects/actionhero/node_modules/ioredis/node_modules/bluebird/js/main/promise.js:697:14)
    at Async._drainQueue (/Users/evantahler/Dropbox/Projects/actionhero/node_modules/ioredis/node_modules/bluebird/js/main/async.js:123:16)
    at Async._drainQueues (/Users/evantahler/Dropbox/Projects/actionhero/node_modules/ioredis/node_modules/bluebird/js/main/async.js:133:10)
    at Immediate.Async.drainQueues [as _onImmediate] (/Users/evantahler/Dropbox/Projects/actionhero/node_modules/ioredis/node_modules/bluebird/js/main/async.js:15:14)
    at processImmediate [as _immediateCallback] (timers.js:383:17)

This only seems to happen when sentinels are in use

@evantahler
Copy link
Author

Oh, I should point out that while the rejection occurs, the message is still received:

> node test.js
PUB connected
SUB connected
Unhandled rejection Error: Connection in subscriber mode, only subscriber commands may be used
    at Redis.sendCommand (/Users/evantahler/Dropbox/Projects/actionhero/node_modules/ioredis/lib/redis.js:500:20)
    at Redis.selectBuffer (/Users/evantahler/Dropbox/Projects/actionhero/node_modules/ioredis/lib/commander.js:117:17)
    at /Users/evantahler/Dropbox/Projects/actionhero/node_modules/ioredis/lib/redis/event_handler.js:184:12
    at /Users/evantahler/Dropbox/Projects/actionhero/node_modules/ioredis/lib/redis/event_handler.js:35:39
    at /Users/evantahler/Dropbox/Projects/actionhero/node_modules/ioredis/lib/redis.js:392:7
    at tryCatcher (/Users/evantahler/Dropbox/Projects/actionhero/node_modules/ioredis/node_modules/bluebird/js/main/util.js:26:23)
    at Promise.successAdapter (/Users/evantahler/Dropbox/Projects/actionhero/node_modules/ioredis/node_modules/bluebird/js/main/nodeify.js:23:30)
    at Promise._settlePromiseAt (/Users/evantahler/Dropbox/Projects/actionhero/node_modules/ioredis/node_modules/bluebird/js/main/promise.js:579:21)
    at Promise._settlePromises (/Users/evantahler/Dropbox/Projects/actionhero/node_modules/ioredis/node_modules/bluebird/js/main/promise.js:697:14)
    at Async._drainQueue (/Users/evantahler/Dropbox/Projects/actionhero/node_modules/ioredis/node_modules/bluebird/js/main/async.js:123:16)
    at Async._drainQueues (/Users/evantahler/Dropbox/Projects/actionhero/node_modules/ioredis/node_modules/bluebird/js/main/async.js:133:10)
    at Immediate.Async.drainQueues [as _onImmediate] (/Users/evantahler/Dropbox/Projects/actionhero/node_modules/ioredis/node_modules/bluebird/js/main/async.js:15:14)
    at processImmediate [as _immediateCallback] (timers.js:383:17)
[channel]: hello

@luin
Copy link
Collaborator

luin commented Feb 19, 2016

Thank you for the feedback! This issue is related with db option instead of sentinel. The following code can reproduce the error:

var redis = new Redis({ db: 10 });
redis.on('connect', function () {
  redis.subscribe('anychannel');
});

The error is because ioredis sends the SELECT command to switch to db 10 on the ready event. In most cases that would not cause any problem because commands sent after the connect event and before the ready event will be added to the offline queue and will be resent after the ready event.

However, pub/sub commands (SUBSCRIBE, PSUBSCRIBE and UNSUBSCRIBE etc) are special that ioredis allows them to be sent to Redis before the ready event. So when we sends SELECT command on the ready event, the connection has been in the subscribe mode and Redis will reject the SELECT command.

@luin luin closed this as completed in 829bf26 Feb 19, 2016
@luin
Copy link
Collaborator

luin commented Feb 19, 2016

Release in 1.15.1 🚀

@evantahler
Copy link
Author

Thanks for the quick patch!

@seunlanlege
Copy link

@luin getting this same error with this code

screenshot from 2018-10-21 19-22-30

@luin
Copy link
Collaborator

luin commented Oct 22, 2018

@seunlanlege This issue has been resolved, so there may be another issue. Could you enable debug mode (DEBUG=ioredis:* node yourapp.js) and post the logs here?

@seunlanlege
Copy link

seunlanlege commented Oct 22, 2018

@luin here are the logs

screenshot from 2018-10-22 18-02-46

@luin
Copy link
Collaborator

luin commented Oct 22, 2018

@seunlanlege What's the constructor argument of Redis? And what's the version of Redis server? Please enable the showFriendlyErrorStack option to see which command cause the exception (new Redis({showFriendlyErrorStack: true})).

@AVVS
Copy link
Contributor

AVVS commented Oct 22, 2018

I think its a problem with the code. Redis.config is issued without await, command cant complete before .subscribe, connection is then moved to subscriber mode and cant finish it

ie I'm pretty sure if you do

await Redis.config()

and only then subscribe - you should be good

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants