-
Notifications
You must be signed in to change notification settings - Fork 170
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
[THREESCALE-2194] Ensure locks are released on configuration_loader. #1050
Conversation
df8243f
to
4c4573f
Compare
t/configuration-loading-lazy.t
Outdated
@@ -75,7 +76,7 @@ env THREESCALE_PORTAL_ENDPOINT=http://127.0.0.1:$TEST_NGINX_SERVER_PORT; | |||
GET /t?user_key=fake | |||
--- error_code: 200 | |||
--- user_files eval | |||
[ | |||
[ |
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.
👀
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.
just empty whitespace on the end of the line. I think that it's good to have it clean :-)
-- @tparam int timeout: timeout for getting the lock before raise an error. | ||
-- @tparam function callback: function to execute if the lock is adquired correctly | ||
function _M:run(key, timeout, callback, ...) | ||
local sema = self:acquire(key) |
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.
acquire
can return an error.
--- run a new function, callback using locks on the given key | ||
-- @tparam string key: key for the semaphore | ||
-- @tparam int timeout: timeout for getting the lock before raise an error. | ||
-- @tparam function callback: function to execute if the lock is adquired correctly |
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.
typo acquired
--- run a new function, callback using locks on the given key | ||
-- @tparam string key: key for the semaphore | ||
-- @tparam int timeout: timeout for getting the lock before raise an error. | ||
-- @tparam function callback: function to execute if the lock is adquired correctly |
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.
Maybe we should also add ...
to the documentation of the function. I can't remember the syntax now.
local task = safe_task.new(callback) | ||
local ret, result = task:execute(...) | ||
|
||
if ok then |
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 lock_acquired
or similar? I think that would make it perfectly clear what this refers to.
sema:post() | ||
end | ||
|
||
return ret, result |
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.
Are 2 enough? According to the docs of the function, execute
returns 2 or 3 params depending on whether there was an error or not.
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.
When there's an error, execute
returns 3 params and the error msg is the third one, so I think we'll lose it.
return false, nil, ret[1] |
@@ -95,3 +96,30 @@ GET /t?user_key=fake | |||
| ] | |||
] | |||
|
|||
=== TEST 4: load invalid json | |||
To validate that process does not died with invalid config |
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'm not sure this test is what we need. I checked that it passes without applying the patch. Also, this description seems to contradict the one in TEST 2.
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.
test 2 validates that the test returns a 404, but the json.decode of an empty string is not going to fail. But json decode of an invalid json will break.
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.
Made this test, looks more legitimate and it's fails:
=== TEST 5: Invalid json structure
To validate that process does not died if the server return an invalid json configuration
--- main_config
env THREESCALE_PORTAL_ENDPOINT=http://127.0.0.1:$TEST_NGINX_SERVER_PORT/;
env APICAST_CONFIGURATION_LOADER=lazy;
--- http_config
include $TEST_NGINX_UPSTREAM_CONFIG;
lua_package_path "$TEST_NGINX_LUA_PATH";
--- config
include $TEST_NGINX_APICAST_CONFIG;
include $TEST_NGINX_BACKEND_CONFIG;
location = /admin/api/nginx/spec.json {
try_files /config.json =404;
}
location /api/ {
echo "all ok";
}
--- request
GET /t?user_key=fake
--- error_code: 404
--- user_files
>>> config.json
{
"services": [{
"id": 1,
"backend_version": 1,
"proxy": {
"api_backend": ["test1", "test2"],
"proxy_rules": [
{ "pattern": "/t", "http_method": "GET", "metric_system_name": "test" }
]
}
}]
}
spec/synchronization.lua
Outdated
local ret, result = synchronization:run(key, 10, callback) | ||
assert.same(ret, true) | ||
assert.same(result, {1}) | ||
assert.spy(callback).was.called() |
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.
o we need the spies? I think that checking the results of run
might be enough.
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.
It's just to make the test completed and easy to understand if someone review the code in future.
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.
👍
sema:post() | ||
else | ||
ngx.log(ngx.WARN, 'failed to acquire lock to lazy load: ', host, ' error: ', err) | ||
local ret, result = synchronization:run(host, 15, lazy.load_config, configuration, host) |
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 define a constant with this 15? I know it's not a problem introduced in this PR, but looks like a good opportunity to fix this.
@@ -196,33 +196,30 @@ function lazy.init(configuration) | |||
configuration.configured = true | |||
end | |||
|
|||
function lazy.load_config(configuration, host) |
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 method is exposed. It should be private, right?
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.
Just checking. Did you forget to change this or decided not to?
ngx.log(ngx.WARN, 'failed to acquire lock to lazy load: ', host, ' error: ', err) | ||
local ret, result = synchronization:run(host, 15, lazy.load_config, configuration, host) | ||
if not ret then | ||
ngx.log(ngx.WARN, 'failed to acquire lock to lazy load: ', host, ' error: ', result) |
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 error message is also shown in the synchronization module. Maybe here we should show a more specific error.
spec/synchronization.lua
Outdated
assert.spy(callback).was_called() | ||
end) | ||
|
||
it("Validates that run does not breaks if a execption on the callback", function() |
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.
typos: break
exception
.
fdc7f23
to
890dfa2
Compare
@@ -9,7 +9,7 @@ local oidc_loader = require 'apicast.configuration_loader.oidc' | |||
local util = require 'apicast.util' | |||
local env = require('resty.env') | |||
local resty_url = require('resty.url') | |||
local synchronization = require('resty.synchronization').new(1) | |||
local synchronization = require('resty.synchronization').new(nil,1) |
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.
Why did this change?
local sema, err = self:acquire(key) | ||
if err ~= key then | ||
ngx.log(ngx.WARN, 'failed to acquire lock on key: ', key, ' error: ', err) | ||
return false, nil |
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.
There's no need for the , nil
8788a7b
to
704f55b
Compare
spec/synchronization.lua
Outdated
assert.spy(callback).was_called() | ||
end) | ||
|
||
it("Validates that run does not break if a exception on the callback", function() |
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.
but there's no exception in this test, right?
spec/synchronization.lua
Outdated
@@ -0,0 +1,78 @@ | |||
describe("Synchronization", function() |
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 file needs to be named sychronization_spec.lua
. Without the _spec
our Makefile will not run the test in this file.
b1a881d
to
89cfb7c
Compare
8cbde7f
to
2c03d0c
Compare
This commits add a new function `run` to the synchronization module, that function ensures that a given function is going to be run in a safe task and make sure that the release of the lock always happens, so the lock is not going to be blocked if something goes wrong. Fix 3scale#1010 Fix THREESCALE-2194 Signed-off-by: Eloy Coto <eloy.coto@gmail.com>
Load an invalid json to make sure that the invalid config does not break the thread. Signed-off-by: Eloy Coto <eloy.coto@gmail.com>
Return a error if the url is not valid for oidc_endpoint and make sure that process does not died due invalid url Signed-off-by: Eloy Coto <eloy.coto@gmail.com>
This commits add a new function
run
to the synchronization module,that function ensures that a given function is going to be run in a safe
task and make sure that the release of the lock always happens, so the
lock is not going to be blocked if something goes wrong.
Fix #1010
Fix THREESCALE-2194