-
Notifications
You must be signed in to change notification settings - Fork 52
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
Fixed the socket adapter config when using ioredis #25
base: master
Are you sure you want to change the base?
Conversation
Hi @Albi34 Couple of things here:
Thanks! |
Hey @sgress454, thanks for the comment ! I'm a bit in an impasse, figuring out why the tests failed made me realize why the From what I gathered, the sails sockets hook creates 2 sets of pub/sub, one for the app itself and one for the admin bus. The solution I proposed will not work since it will reuse the same pub and sub clients for the two "channels" (instead of having two distinct adapters we have only one that we reuse). What I would propose is to instantiate the ioredis clients directly within the prepare-driver.js script. There is already something kind of similar using the node-redis module:
My solution would be to allow to configure which client to use here, basically offering users the choice between the basic node-redis or the more advanced ioredis. For that purpose I would implement the following changes :
Here is what the config would look like:
That way, we'd keep the Not sure if that fits with the way you want this module to work though, any thoughts ? I'll update the PR with this once I'm done but I would understand if you find this not generic enough. |
I updated the PR with the solution I described above. It's working for my specific use-case. It should not create any conflict with the current configuration, I made sure that all unit tests are passing. If you want to merge it, let me know and I'll include some additional unit tests to check the new features. It's used in conjunction with the other PR here: /pull/26 For reference, here is the configuration I'm using in my sails app:
|
…pecified client config.
@sgress454 @mikermcneil Is this going to be merged and released at some point? At the moment relying on @Albi34 's git repo on npm installs, which isn't a great solution. Anyone with a proper failover production redis setup would be be using ioredis, node_redis does does not have sentinel or cluster support yet (we're working on this, but we're currently in the process of standardising both redis libs to use common packages etc) |
@sgress454 Ok, thanks for keeping us posted. |
@Albi34 @sgress454 @Salakar Hey guys, as long as this maintains full compatibility, the necessary tweaks are made to make the tests pass, and we update the sails.config.sockets documentation, I'm ok with this being in sails-hook-sockets. Thanks for the help! |
Sorry for the delay, I just merged my changes with the latest master here and made a duplicate of the basic unit tests suite for the "with-redis" test case but with another client (ioredis, which I added in the packages.json + the latest version of socket-io.redis which supports this client). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I went through and took a look at everything. My takeaway is that this is a solid approach, but it's not something we can maintain for Sails (because e.g. why just ioredis? what about >>insert redis client library here<< etc.)
So instead, I'd like to tackle this a little differently: by exposing a createClient
function (or comparable) in the config.
I need to get a bit more up to speed about what has changed here before I can comment further, but just wanted to take the time to give you feedback ASAP.
Thanks for all your hard work, and for getting us on the right track!
@@ -70,6 +70,12 @@ module.exports = function ToConfigure(app) { | |||
if (app.config.sockets.subClient) { | |||
app.config.sockets.adapterOptions.subClient = app.config.sockets.subClient; | |||
} | |||
if (app.config.sockets.adapterClientConfig) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we name this redisClientOpts
instead?
if (app.config.sockets.adapterClientConfig) { | ||
app.config.sockets.adapterOptions.adapterClientConfig = app.config.sockets.adapterClientConfig; | ||
} | ||
if (app.config.sockets.adapterClientName) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of expecting the package name, can we allow an override to be passed in from userland? i.e. if app.config.sockets.redisLibrary
is defined, then the automatic require()
below can be skipped. Also, this way, none of the existing auto-require() stuff will need to change
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also note that this means that the redis client library can be a direct dependency of your app, allowing you to switch out to use any *redis client library in the future
@@ -16,53 +16,67 @@ module.exports = function (app){ | |||
var adapterModuleName = adapterDef.moduleName; | |||
var pathToAdapterDependency = adapterDef.modulePath; | |||
var adapterConfig = adapterDef.config; | |||
var adapterClientName = adapterConfig.adapterClientName || 'redis'; | |||
var adapterClientConfig = adapterConfig.adapterClientConfig || {}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(See above about renaming this redisClientOpts
)
@@ -16,53 +16,67 @@ module.exports = function (app){ | |||
var adapterModuleName = adapterDef.moduleName; | |||
var pathToAdapterDependency = adapterDef.modulePath; | |||
var adapterConfig = adapterDef.config; | |||
var adapterClientName = adapterConfig.adapterClientName || 'redis'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See above-- instead of var adapterClientName = adapterConfig.adapterClientName || 'redis'
, this can be simplified to:
var redisLibrary = adapterConfig.redisLibrary;
|
||
// For redis: | ||
// ============================================================ | ||
if (adapterModuleName === 'socket.io-redis') { | ||
|
||
// Create raw redis clients if necessary | ||
var rawClientsNecessary = adapterConfig.pass || adapterConfig.db || adapterDef.adminBus; | ||
var rawClientsNecessary = adapterConfig.pass || adapterConfig.db || adapterDef.adminBus || adapterConfig.adapterClientConfig; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
=> adapterConfig.redisClientOpts
(see above)
|
||
loadHooks: ['moduleloader', 'userconfig', 'http', 'sockets'], | ||
|
||
// Configure the socket.io-redis adapter |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd like to extrapolate these tests in some way to prevent duplication, but I can help with that later. But just want to check first-- is this identical to the existing tests other than the change to the redis client library in the config?
@@ -23,7 +23,8 @@ | |||
"mocha": "^2.2.4", | |||
"sails": "balderdashy/sails", | |||
"sails.io.js": "^0.13.0", | |||
"socket.io-redis": "^1.0.0" | |||
"ioredis": "^2.2.0", | |||
"socket.io-redis": "git+https://github.com/socketio/socket.io-redis.git" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would you leave the SVR of socket.io-redis
as is or change it to^1.1.1
?
// If `pass` was supplied, pass it in as `auth_pass` | ||
if (adapterConfig.pass) { | ||
|
||
redisClientOpts.auth_pass = adapterConfig.pass; | ||
adapterClientConfig.auth_pass = adapterConfig.pass; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
=> redisClientOpts
} | ||
} | ||
|
||
// Set up object that will be used for redis client options | ||
var redisClientOpts = {}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will now be at the top (see other comments) -- and let's please preserve the code comment:
// Set up object that will be used for redis client options
|
||
var initiateRedisClient = function(adapterConfig, redis, adapterClientName, adapterClientConfig){ | ||
if(adapterClientName === 'ioredis'){ | ||
return new redis(adapterClientConfig); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the tricky part to deal with-- since every redis client library has its own usage, the configured clientLibrary will have to be ducktyped, or we'd have to ask for the package name as well. It seems like a better solution here might be, instead of expecting a reference to a Redis client library and/or to the package name, we accepted a createClient function.... I'll follow up on that momentarily.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
^^ a la what Express does with consolidate & view engines (and what we're moving toward for sails v1). This way, we could easily include configuration for ioredis and any other redis client library that comes along in the future (meanwhile, for folks who are cool with the default redis client from inside socket.io-redis
, they should be able to use everything as-is).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
^^and in that case, we won't need to add sails.config.sockets.redisClientOpts
either, since that will be completely flexible
@Albi34 hmm... would you say it's true that, before this PR, you could achieve the same effect by doing the following in your config? pubClient: (function (){
var ioredis = require('ioredis');
return new ioredis({
// ... my custom io redis opts
});
})(),
subClient: (function (){
var ioredis = require('ioredis');
return new ioredis({
// ... my custom io redis opts
});
})(), |
@Albi34 I'm under the impression that e7a534e#diff-a1f6827ffd3f94fc77c76b6c445eaf27R37 cc @sgress454 |
Hi @mikermcneil, thanks for all the input ! I'll try to go through it tomorrow when I have some time, it's been pretty busy lately :) I have to admit that I haven't checked the code base in the past couple of months (since the PR was opened back in May) so you're right, it's possible that the changes I tried to implement here are now supported in the current master. For your question about the changes being supported at the time I created this PR, it was in fact not possible to do it through the config because of the following lines in the prepare-adapter.js:
The lodash cloneDeep function was not able to properly clone the ioredis client (I investigated it at the time, I remember it had to do with the way the ioredis client was initialized but I can't recall all the details). Since these two lines are still present, I guess it's still not supporting Ioredis, except if the client changed in the meantime or if lodash had an update concerning the cloneDeep function, I'll give it a try as soon as I can. |
@Albi34 ahh ok gotcha. So it sounds like maybe the solution here is just to remove the cloning? We should still trace the code to make sure that doesn't break any assumptions, but off the top of my head, that shouldn't be a problem. If you do have a moment to do a PR with that (or change this one), that'd be awesome, otherwise Scott or I will follow up as soon as we can. Thanks again! |
@Albi34 just confirmed with @sgress454 and there are now tests that use |
@sgress454 @mikermcneil I am trying to upgrade to sails^1.0.0 specifically so that I could use socket.io^2.0.0 and ioredis. What should I do in order to do that? It seems the current version of sails-hook-sockets on npm uses a v1.7.3 of socket.io (which is incompatible with the latest version of socket.io-redis) nvm, I pulled master and got it working with socket.io^2.0.0 Is there any reason that the latest version of master isn't on npm? I'd put this comment in an issue but it doesn't look like issues are enabled for this repo... |
This is a fix for the issue balderdashy/sails-hook-sockets/issues/24
Let me know if you have any questions !