Skip to content

Commit 03dff6d

Browse files
piotrppintsized
authored andcommitted
Don't send SELECT + ROLE commands to Sentinels
1 parent 02a29f9 commit 03dff6d

File tree

3 files changed

+80
-34
lines changed

3 files changed

+80
-34
lines changed

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -197,16 +197,16 @@ the server
197197

198198
`syntax: rc = redis_connector.new(params)`
199199

200-
Creates the Redis Connector object, overring default params with the ones given.
200+
Creates the Redis Connector object, overriding default params with the ones given.
201201
In case of failures, returns `nil` and a string describing the error.
202202

203203

204204
### connect
205205

206206
`syntax: redis, err = rc:connect(params)`
207207

208-
Attempts to create a connection, according to the [params](#parameters)
209-
supplied, falling back to defaults given in `new` or the predefined defaults. If
208+
Attempts to create a connection, according to the `params` supplied, falling back
209+
to [defaults](#default-parameters) given in `new` or the predefined defaults. If
210210
a connection cannot be made, returns `nil` and a string describing the reason.
211211

212212
Note that `params` given here do not change the connector's own configuration,

lib/resty/redis/connector.lua

Lines changed: 40 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,36 @@
1-
local ipairs, pcall, error, tostring, type, next, setmetatable, getmetatable =
2-
ipairs, pcall, error, tostring, type, next, setmetatable, getmetatable
1+
local ipairs, pairs, pcall, error, tostring, type, next, setmetatable, getmetatable =
2+
ipairs, pairs, pcall, error, tostring, type, next, setmetatable, getmetatable
33

44
local ngx_log = ngx.log
55
local ngx_ERR = ngx.ERR
66
local ngx_re_match = ngx.re.match
7+
local null = ngx.null
78

89
local str_find = string.find
910
local str_sub = string.sub
1011
local tbl_remove = table.remove
1112
local tbl_sort = table.sort
12-
local ok, tbl_new = pcall(require, "table.new")
13-
if not ok then
14-
tbl_new = function (narr, nrec) return {} end -- luacheck: ignore 212
13+
local tbl_clone, tbl_new
14+
do
15+
local ok
16+
ok, tbl_new = pcall(require, "table.new")
17+
if not ok then
18+
tbl_new = function (narr, nrec) return {} end -- luacheck: ignore 212
19+
end
20+
ok, tbl_clone = pcall(require, "table.clone")
21+
if not ok then
22+
tbl_clone = function (src)
23+
local result = {}
24+
for i, v in ipairs(src) do
25+
result[i] = v
26+
end
27+
for k, v in pairs(src) do
28+
result[k] = v
29+
end
30+
31+
return result
32+
end
33+
end
1534
end
1635

1736
local redis = require("resty.redis")
@@ -253,19 +272,19 @@ end
253272

254273

255274
function _M.connect_via_sentinel(self, params)
256-
local sentinels = params.sentinels
257275
local master_name = params.master_name
258276
local role = params.role
259277
local db = params.db
260278
local username = params.username
261279
local password = params.password
262-
local sentinel_username = params.sentinel_username
263-
local sentinel_password = params.sentinel_password
264-
if sentinel_password then
265-
for _, host in ipairs(sentinels) do
266-
host.username = sentinel_username
267-
host.password = sentinel_password
268-
end
280+
281+
local sentinels = tbl_new(#params.sentinels, 0)
282+
for i, sentinel in ipairs(params.sentinels) do
283+
local host = tbl_clone(sentinel)
284+
host.db = null
285+
host.username = host.username or params.sentinel_username
286+
host.password = host.password or params.sentinel_password
287+
sentinels[i] = host
269288
end
270289

271290
local sentnl, err, previous_errors = self:try_hosts(sentinels)
@@ -344,7 +363,7 @@ function _M.connect_to_host(self, host)
344363

345364
-- config options in 'host' should override the global defaults
346365
-- host contains keys that aren't in config
347-
-- this can break tbl_copy_merge_defaults, hence the mannual loop here
366+
-- this can break tbl_copy_merge_defaults, hence the manual loop here
348367
local config = tbl_copy(self.config)
349368
for k, _ in pairs(config) do
350369
if host[k] then
@@ -402,20 +421,20 @@ function _M.connect_to_host(self, host)
402421
end
403422
end
404423

405-
-- No support for DBs in proxied Redis.
406-
if config.connection_is_proxied ~= true and host.db ~= nil then
407-
local res, err = r:select(host.db)
424+
-- No support for DBs in proxied Redis and Redis Sentinel
425+
if config.connection_is_proxied ~= true and host.db ~= nil and host.db ~= null then
426+
local res, select_err = r:select(host.db)
408427

409428
-- SELECT will fail if we are connected to sentinel:
410429
-- detect it and ignore error message it that's the case
411-
if err and str_find(err, "ERR unknown command") then
430+
if select_err and str_find(select_err, "ERR unknown command") then
412431
local role = r:role()
413432
if role and role[1] == "sentinel" then
414-
err = nil
433+
select_err = nil
415434
end
416435
end
417-
if err then
418-
return res, err
436+
if select_err then
437+
return res, select_err
419438
end
420439
end
421440
return r, nil

t/sentinel.t

Lines changed: 37 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -26,15 +26,42 @@ run_tests();
2626

2727
__DATA__
2828
29-
=== TEST 1: Get the master
29+
=== TEST 1: Connect using redis:// protocol
30+
--- http_config eval: $::HttpConfig
31+
--- config
32+
location /t {
33+
content_by_lua_block {
34+
local rc = require("resty.redis.connector").new()
35+
local sentinel, err, pong
36+
37+
sentinel, err = rc:connect{ url = "redis://127.0.0.1:$TEST_NGINX_SENTINEL_PORT1", db = ngx.null }
38+
assert(sentinel and not err, "sentinel should connect without errors but got " .. tostring(err))
39+
pong, err = sentinel:ping()
40+
assert(pong and not err, "sentinel should respond to PING got " .. tostring(err))
41+
sentinel:close()
42+
43+
sentinel, err = rc:connect{ url = "redis://127.0.0.1:$TEST_NGINX_SENTINEL_PORT1", db = 0 }
44+
assert(sentinel and not err, "sentinel should connect with db=0 without errors but got " .. tostring(err))
45+
pong, err = sentinel:ping()
46+
assert(pong and not err, "sentinel should respond to PING got " .. tostring(err))
47+
sentinel:close()
48+
}
49+
}
50+
--- request
51+
GET /t
52+
--- no_error_log
53+
[error]
54+
55+
56+
=== TEST 2: Get the master
3057
--- http_config eval: $::HttpConfig
3158
--- config
3259
location /t {
3360
content_by_lua_block {
3461
local rc = require("resty.redis.connector").new()
3562
local rs = require("resty.redis.sentinel")
3663
37-
local sentinel, err = rc:connect{ url = "redis://127.0.0.1:$TEST_NGINX_SENTINEL_PORT1" }
64+
local sentinel, err = rc:connect{ url = "redis://127.0.0.1:$TEST_NGINX_SENTINEL_PORT1", db = ngx.null }
3865
assert(sentinel and not err, "sentinel should connect without errors but got " .. tostring(err))
3966
4067
local master, err = rs.get_master(sentinel, "mymaster")
@@ -57,7 +84,7 @@ GET /t
5784
[error]
5885
5986
60-
=== TEST 1b: Get the master directly
87+
=== TEST 2b: Get the master directly
6188
--- http_config eval: $::HttpConfig
6289
--- config
6390
location /t {
@@ -84,15 +111,15 @@ GET /t
84111
[error]
85112
86113
87-
=== TEST 2: Get slaves
114+
=== TEST 3: Get slaves
88115
--- http_config eval: $::HttpConfig
89116
--- config
90117
location /t {
91118
content_by_lua_block {
92119
local rc = require("resty.redis.connector").new()
93120
local rs = require("resty.redis.sentinel")
94121
95-
local sentinel, err = rc:connect{ url = "redis://127.0.0.1:$TEST_NGINX_SENTINEL_PORT1" }
122+
local sentinel, err = rc:connect{ url = "redis://127.0.0.1:$TEST_NGINX_SENTINEL_PORT1", db = ngx.null }
96123
assert(sentinel and not err, "sentinel should connect without error")
97124
98125
local slaves, err = rs.get_slaves(sentinel, "mymaster")
@@ -121,14 +148,14 @@ location /t {
121148
[error]
122149
123150
124-
=== TEST 3: Get only healthy slaves
151+
=== TEST 4: Get only healthy slaves
125152
--- http_config eval: $::HttpConfig
126153
--- config
127154
location /t {
128155
content_by_lua_block {
129156
local rc = require("resty.redis.connector").new()
130157
131-
local sentinel, err = rc:connect({ url = "redis://127.0.0.1:$TEST_NGINX_SENTINEL_PORT1" })
158+
local sentinel, err = rc:connect({ url = "redis://127.0.0.1:$TEST_NGINX_SENTINEL_PORT1", db = ngx.null })
132159
assert(sentinel and not err, "sentinel should connect without error")
133160
134161
local slaves, err = require("resty.redis.sentinel").get_slaves(
@@ -183,7 +210,7 @@ GET /t
183210
[error]
184211
185212
186-
=== TEST 4: connector.connect_via_sentinel
213+
=== TEST 5: connector.connect_via_sentinel
187214
--- http_config eval: $::HttpConfig
188215
--- config
189216
location /t {
@@ -215,7 +242,7 @@ GET /t
215242
[error]
216243
217244
218-
=== TEST 5: regression for slave sorting (iss12)
245+
=== TEST 6: regression for slave sorting (iss12)
219246
--- http_config eval: $::HttpConfig
220247
--- config
221248
location /t {
@@ -252,7 +279,7 @@ GET /t
252279
--- no_error_log
253280
[error]
254281
255-
=== TEST 6: connect with acl
282+
=== TEST 7: connect with acl
256283
--- http_config eval: $::HttpConfig
257284
--- config
258285
location /t {

0 commit comments

Comments
 (0)