Skip to content

Commit 7b8bd09

Browse files
authored
feat/send timeout (#42)
* convert tabs to spaces * add send_timeout parameter For backwards compatibility, if the user gives a `read_timeout` but no `send_timeout`, we assume they want a `send_timeout` matching their `read_timeout`. If neither are given, the defaults apply. * fallback send_timeout in all cases We must do this for connector level config, as well as connection level config. Also moved dsn fallbacks into a utility function. * format readme for better source readability * document send_timeout * add tests for send timeout backwards compatibility * suppress socket errors There are spurious socket errors in the logs when using `tcpsock:settimeouts` which only appear in certain environments and are not related to the socket being tested. The socket is not in an error state, and all of our tests pass with proper checks for errors. So we now suppress the built in errors, as recommended in the lua-nginx-module docs. * bump nginx to 1.19.9 Something is broken in the openresty patch set, but modules using 1.19.9 seem to build in travis fine.
1 parent 9d53749 commit 7b8bd09

File tree

7 files changed

+247
-115
lines changed

7 files changed

+247
-115
lines changed

.travis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ env:
3535
- TEST_NGINX_SLEEP=0.006
3636
- LUACHECK_VER=0.21.1
3737
jobs:
38-
- NGINX_VERSION=1.17.8
38+
- NGINX_VERSION=1.19.9
3939

4040
before_install:
4141
# we can't update redis in addons.apt.packages as updated package automatically tries to start and immediately fails

README.md

Lines changed: 79 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
11
# lua-resty-redis-connector
22

3-
[![Build Status](https://travis-ci.org/ledgetech/lua-resty-redis-connector.svg?branch=master)](https://travis-ci.org/ledgetech/lua-resty-redis-connector)
3+
[![Build
4+
Status](https://travis-ci.org/ledgetech/lua-resty-redis-connector.svg?branch=master)](https://travis-ci.org/ledgetech/lua-resty-redis-connector)
45

5-
Connection utilities for [lua-resty-redis](https://github.com/openresty/lua-resty-redis), making it easy and reliable to connect to Redis hosts, either directly or via [Redis Sentinel](http://redis.io/topics/sentinel).
6+
Connection utilities for
7+
[lua-resty-redis](https://github.com/openresty/lua-resty-redis), making it easy
8+
and reliable to connect to Redis hosts, either directly or via [Redis
9+
Sentinel](http://redis.io/topics/sentinel).
610

711

812
## Synopsis
@@ -20,6 +24,7 @@ More verbose configuration, with timeouts and a default password:
2024
```lua
2125
local rc = require("resty.redis.connector").new({
2226
connect_timeout = 50,
27+
send_timeout = 5000,
2328
read_timeout = 5000,
2429
keepalive_timeout = 30000,
2530
password = "mypass",
@@ -39,6 +44,7 @@ Keep all config in a table, to easily create / close connections as needed:
3944
```lua
4045
local rc = require("resty.redis.connector").new({
4146
connect_timeout = 50,
47+
send_timeout = 5000,
4248
read_timeout = 5000,
4349
keepalive_timeout = 30000,
4450

@@ -55,7 +61,8 @@ local redis, err = rc:connect()
5561
local ok, err = rc:set_keepalive(redis)
5662
```
5763

58-
[connect](#connect) can be used to override some defaults given in [new](#new), which are pertinent to this connection only.
64+
[connect](#connect) can be used to override some defaults given in [new](#new),
65+
which are pertinent to this connection only.
5966

6067

6168
```lua
@@ -73,17 +80,20 @@ local redis, err = rc:connect({
7380

7481
## DSN format
7582

76-
If the `params.url` field is present then it will be parsed to set the other params. Any manually specified params will override values given in the DSN.
83+
If the `params.url` field is present then it will be parsed to set the other
84+
params. Any manually specified params will override values given in the DSN.
7785

78-
*Note: this is a behaviour change as of v0.06. Previously, the DSN values would take precedence.*
86+
*Note: this is a behaviour change as of v0.06. Previously, the DSN values would
87+
take precedence.*
7988

8089
### Direct Redis connections
8190

8291
The format for connecting directly to Redis is:
8392

8493
`redis://USERNAME:PASSWORD@HOST:PORT/DB`
8594

86-
The `USERNAME`, `PASSWORD` and `DB` fields are optional, all other components are required.
95+
The `USERNAME`, `PASSWORD` and `DB` fields are optional, all other components
96+
are required.
8797

8898
Use of username requires Redis 6.0.0 or newer.
8999

@@ -93,10 +103,13 @@ When connecting via Redis Sentinel, the format is as follows:
93103

94104
`sentinel://USERNAME:PASSWORD@MASTER_NAME:ROLE/DB`
95105

96-
Again, `USERNAME`, `PASSWORD` and `DB` are optional. `ROLE` must be either `m` or `s` for master / slave respectively.
106+
Again, `USERNAME`, `PASSWORD` and `DB` are optional. `ROLE` must be either `m`
107+
or `s` for master / slave respectively.
97108

98-
On versions of Redis newer than 5.0.1, Sentinels can optionally require their own password. If enabled, provide this password in the `sentinel_password` parameter.
99-
On Redis 6.2.0 and newer you can pass username using `sentinel_username` parameter.
109+
On versions of Redis newer than 5.0.1, Sentinels can optionally require their
110+
own password. If enabled, provide this password in the `sentinel_password`
111+
parameter. On Redis 6.2.0 and newer you can pass username using
112+
`sentinel_username` parameter.
100113

101114
A table of `sentinels` must also be supplied. e.g.
102115

@@ -113,31 +126,40 @@ local redis, err = rc:connect{
113126

114127
## Proxy Mode
115128

116-
Enable the `connection_is_proxied` parameter if connecting to Redis through a proxy service (e.g. Twemproxy).
117-
These proxies generally only support a limited sub-set of Redis commands, those which do not require state and do not affect multiple keys.
118-
Databases and transactions are also not supported.
129+
Enable the `connection_is_proxied` parameter if connecting to Redis through a
130+
proxy service (e.g. Twemproxy). These proxies generally only support a limited
131+
sub-set of Redis commands, those which do not require state and do not affect
132+
multiple keys. Databases and transactions are also not supported.
119133

120-
Proxy mode will disable switching to a DB on connect.
121-
Unsupported commands (defaults to those not supported by Twemproxy) will return `nil, err` immediately rather than being sent to the proxy, which can result in dropped connections.
134+
Proxy mode will disable switching to a DB on connect. Unsupported commands
135+
(defaults to those not supported by Twemproxy) will return `nil, err`
136+
immediately rather than being sent to the proxy, which can result in dropped
137+
connections.
122138

123139
`discard` will not be sent when adding connections to the keepalive pool
124140

125141

126142
## Disabled commands
127143

128-
If configured as a table of commands, the command methods will be replaced by a function which immediately returns `nil, err` without forwarding the command to the server
144+
If configured as a table of commands, the command methods will be replaced by a
145+
function which immediately returns `nil, err` without forwarding the command to
146+
the server
129147

130148
## Default Parameters
131149

132150

133151
```lua
134152
{
135153
connect_timeout = 100,
154+
send_timeout = 1000,
136155
read_timeout = 1000,
137-
connection_options = {}, -- pool, etc
138156
keepalive_timeout = 60000,
139157
keepalive_poolsize = 30,
140158

159+
-- ssl, ssl_verify, server_name, pool, pool_size, backlog
160+
-- see: https://github.com/openresty/lua-resty-redis#connect
161+
connection_options = {},
162+
141163
host = "127.0.0.1",
142164
port = "6379",
143165
path = "", -- unix socket path, e.g. /tmp/redis.sock
@@ -175,16 +197,21 @@ If configured as a table of commands, the command methods will be replaced by a
175197

176198
`syntax: rc = redis_connector.new(params)`
177199

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

180203

181204
### connect
182205

183206
`syntax: redis, err = rc:connect(params)`
184207

185-
Attempts to create a connection, according to the [params](#parameters) supplied, falling back to defaults given in `new` or the predefined defaults. If a connection cannot be made, returns `nil` and a string describing the reason.
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
210+
a connection cannot be made, returns `nil` and a string describing the reason.
186211

187-
Note that `params` given here do not change the connector's own configuration, and are only used to alter this particular connection operation. As such, the following parameters have no meaning when given in `connect`.
212+
Note that `params` given here do not change the connector's own configuration,
213+
and are only used to alter this particular connection operation. As such, the
214+
following parameters have no meaning when given in `connect`.
188215

189216
* `keepalive_poolsize`
190217
* `keepalive_timeout`
@@ -196,24 +223,28 @@ Note that `params` given here do not change the connector's own configuration, a
196223

197224
`syntax: ok, err = rc:set_keepalive(redis)`
198225

199-
Attempts to place the given Redis connection on the keepalive pool, according to timeout and poolsize params given in `new` or the predefined defaults.
226+
Attempts to place the given Redis connection on the keepalive pool, according to
227+
timeout and poolsize params given in `new` or the predefined defaults.
200228

201-
This allows an application to release resources without having to keep track of application wide keepalive settings.
229+
This allows an application to release resources without having to keep track of
230+
application wide keepalive settings.
202231

203232
Returns `1` or in the case of error, `nil` and a string describing the error.
204233

205234

206235
## Utilities
207236

208-
The following methods are not typically needed, but may be useful if a custom interface is required.
237+
The following methods are not typically needed, but may be useful if a custom
238+
interface is required.
209239

210240

211241
### connect_via_sentinel
212242

213243
`syntax: redis, err = rc:connect_via_sentinel(params)`
214244

215-
Returns a Redis connection by first accessing a sentinel as supplied by the `params.sentinels` table,
216-
and querying this with the `params.master_name` and `params.role`.
245+
Returns a Redis connection by first accessing a sentinel as supplied by the
246+
`params.sentinels` table, and querying this with the `params.master_name` and
247+
`params.role`.
217248

218249

219250
### try_hosts
@@ -234,14 +265,16 @@ Attempts to connect to the supplied `host`.
234265

235266
`syntax: master, err = sentinel.get_master(sentinel, master_name)`
236267

237-
Given a connected Sentinel instance and a master name, will return the current master Redis instance.
268+
Given a connected Sentinel instance and a master name, will return the current
269+
master Redis instance.
238270

239271

240272
### sentinel.get_slaves
241273

242274
`syntax: slaves, err = sentinel.get_slaves(sentinel, master_name)`
243275

244-
Given a connected Sentinel instance and a master name, will return a list of registered slave Redis instances.
276+
Given a connected Sentinel instance and a master name, will return a list of
277+
registered slave Redis instances.
245278

246279

247280
# Author
@@ -257,10 +290,23 @@ Copyright (c) James Hurst <james@pintsized.co.uk>
257290

258291
All rights reserved.
259292

260-
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
261-
262-
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
263-
264-
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
265-
266-
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
293+
Redistribution and use in source and binary forms, with or without modification,
294+
are permitted provided that the following conditions are met:
295+
296+
* Redistributions of source code must retain the above copyright notice, this
297+
list of conditions and the following disclaimer.
298+
299+
* Redistributions in binary form must reproduce the above copyright notice, this
300+
list of conditions and the following disclaimer in the documentation and/or
301+
other materials provided with the distribution.
302+
303+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
304+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
305+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
306+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
307+
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
308+
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
309+
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
310+
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
311+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
312+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

lib/resty/redis/connector.lua

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ end
8989
local DEFAULTS = setmetatable({
9090
connect_timeout = 100,
9191
read_timeout = 1000,
92+
send_timeout = 1000,
9293
connection_options = {}, -- pool, etc
9394
keepalive_timeout = 60000,
9495
keepalive_poolsize = 30,
@@ -185,13 +186,30 @@ end
185186
_M.parse_dsn = parse_dsn
186187

187188

188-
function _M.new(config)
189-
-- Fill out gaps in config with any dsn params
189+
-- Fill out gaps in config with any dsn params
190+
local function apply_dsn(config)
190191
if config and config.url then
191192
local err
192193
config, err = parse_dsn(config)
193194
if err then ngx_log(ngx_ERR, err) end
194195
end
196+
return config
197+
end
198+
199+
200+
-- For backwards compatability; previously send_timeout was implicitly the
201+
-- same as read_timeout. So if only the latter is given, ensure the former
202+
-- matches.
203+
local function apply_fallback_send_timeout(config)
204+
if config and not config.send_timeout and config.read_timeout then
205+
config.send_timeout = config.read_timeout
206+
end
207+
end
208+
209+
210+
function _M.new(config)
211+
config = apply_dsn(config)
212+
apply_fallback_send_timeout(config)
195213

196214
local ok, config = pcall(tbl_copy_merge_defaults, config, DEFAULTS)
197215
if not ok then
@@ -212,11 +230,8 @@ end
212230

213231

214232
function _M.connect(self, params)
215-
if params and params.url then
216-
local err
217-
params, err = parse_dsn(params)
218-
if err then ngx_log(ngx_ERR, err) end
219-
end
233+
params = apply_dsn(params)
234+
apply_fallback_send_timeout(params)
220235

221236
params = tbl_copy_merge_defaults(params, self.config)
222237

@@ -337,7 +352,11 @@ function _M.connect_to_host(self, host)
337352
end
338353
end
339354

340-
r:set_timeout(config.connect_timeout)
355+
r:set_timeouts(
356+
config.connect_timeout,
357+
config.send_timeout,
358+
config.read_timeout
359+
)
341360

342361
-- Stub out methods for disabled commands
343362
if next(config.disabled_commands) then
@@ -368,8 +387,6 @@ function _M.connect_to_host(self, host)
368387
if not ok then
369388
return nil, err
370389
else
371-
r:set_timeout(config.read_timeout)
372-
373390
local username = host.username
374391
local password = host.password
375392
if password and password ~= "" then

0 commit comments

Comments
 (0)