diff --git a/gateway/src/apicast/threescale_utils.lua b/gateway/src/apicast/threescale_utils.lua index d634178f0..6c1559313 100644 --- a/gateway/src/apicast/threescale_utils.lua +++ b/gateway/src/apicast/threescale_utils.lua @@ -124,7 +124,7 @@ function _M.connect_redis(options) local opts = {} local url = options and options.url or env.get('REDIS_URL') - + local resilient = options.resilient if url then url = resty_url.split(url, 'redis') @@ -151,15 +151,24 @@ function _M.connect_redis(options) red:set_timeout(opts.timeout) local ok, err = red:connect(_M.resolve(host, port)) + if not ok then - return nil, _M.error("failed to connect to redis on ", host, ":", port, ": ", err) + if not resilient then + return nil, _M.error("failed to connect to redis on ", host, ":", port, ": ", err) + else + return nil, _M.error_gracefully("failed to connect to redis on ", host, ":", port, ": ", err) + end end if opts.password then ok = red:auth(opts.password) if not ok then - return nil, _M.error("failed to auth on redis ", host, ":", port) + if not resilient then + return nil, _M.error("failed to auth on redis ", host, ":", port) + else + return nil, _M.error_gracefully("failed to auth on redis ", host, ":", port) + end end end @@ -167,7 +176,11 @@ function _M.connect_redis(options) ok = red:select(opts.db) if not ok then - return nil, _M.error("failed to select db ", opts.db, " on redis ", host, ":", port) + if not resilient then + return nil, _M.error("failed to select db ", opts.db, " on redis ", host, ":", port) + else + return nil, _M.error_gracefully("failed to select db ", opts.db, " on redis ", host, ":", port) + end end end @@ -187,17 +200,25 @@ function _M.match_xml_element(xml, element, value) return string.find(xml, pattern, xml_header_len, xml_header_len, true) end --- error and exit -function _M.error(...) +-- error without exit +function _M.error_gracefully(...) if ngx.get_phase() == 'timer' then return table.concat(table.pack(...)) else ngx.status = ngx.HTTP_INTERNAL_SERVER_ERROR ngx.say(...) - ngx.exit(ngx.status) end end +-- error and exit +function _M.error(...) + local err = _M.error_gracefully(...) + if err then + return err + end + ngx.exit(ngx.status) +end + function _M.missing_args(text) ngx.say(text) ngx.exit(ngx.HTTP_OK) diff --git a/spec/threescale_utils_spec.lua b/spec/threescale_utils_spec.lua index 04ca1cf36..fe45c326b 100644 --- a/spec/threescale_utils_spec.lua +++ b/spec/threescale_utils_spec.lua @@ -10,5 +10,27 @@ describe('3scale utils', function() assert.equal('one two three', error) end) + + it('.error fails the nginx chain', function() + stub(ngx, 'get_phase', function() return 'init' end) + stub(ngx, 'say', function(...) return nil end) + local exit = spy.on(ngx, 'exit', function(s) return 'exited!' end) + + local error = _M.error('cache issue ' .. 'host:' .. 6379) + + assert.spy(ngx.exit).was_called(1) + assert.spy(ngx.say).was.called_with('cache issue ' .. 'host:' .. 6379) + end) + + it('.error_gracefully logs the error without exiting chain', function() + stub(ngx, 'get_phase', function() return 'init' end) + stub(ngx, 'say', function(...) return nil end) + + local exit = spy.on(ngx, 'exit', function(s) return 'exited!' end) + local error = _M.error_gracefully('redis is not reachable') + + assert.spy(ngx.exit).was_not_called() + assert.spy(ngx.say).was.called_with('redis is not reachable') + end) end) end)