Skip to content
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

Merged
merged 3 commits into from
Jun 6, 2019

Conversation

eloycoto
Copy link
Contributor

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

@eloycoto eloycoto requested a review from a team as a code owner May 29, 2019 09:22
@eloycoto eloycoto force-pushed the Issue-1010 branch 2 times, most recently from df8243f to 4c4573f Compare May 29, 2019 09:41
@@ -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
[
[
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👀

Copy link
Contributor Author

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)
Copy link
Contributor

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
Copy link
Contributor

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
Copy link
Contributor

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
Copy link
Contributor

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
Copy link
Contributor

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.

Copy link
Contributor

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.

@@ -95,3 +96,30 @@ GET /t?user_key=fake
| ]
]

=== TEST 4: load invalid json
To validate that process does not died with invalid config
Copy link
Contributor

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.

Copy link
Contributor Author

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.

Copy link
Contributor Author

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" }
        ]
      }
    }]
}

local ret, result = synchronization:run(key, 10, callback)
assert.same(ret, true)
assert.same(result, {1})
assert.spy(callback).was.called()
Copy link
Contributor

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.

Copy link
Contributor Author

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.

Copy link
Contributor

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)
Copy link
Contributor

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)
Copy link
Contributor

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?

Copy link
Contributor

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)
Copy link
Contributor

@davidor davidor May 29, 2019

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.

assert.spy(callback).was_called()
end)

it("Validates that run does not breaks if a execption on the callback", function()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typos: break exception.

@eloycoto eloycoto force-pushed the Issue-1010 branch 4 times, most recently from fdc7f23 to 890dfa2 Compare May 31, 2019 13:36
@eloycoto eloycoto requested a review from davidor June 3, 2019 16:03
@@ -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)
Copy link
Contributor

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
Copy link
Contributor

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

@eloycoto eloycoto force-pushed the Issue-1010 branch 3 times, most recently from 8788a7b to 704f55b Compare June 6, 2019 09:21
@eloycoto eloycoto requested a review from davidor June 6, 2019 09:23
assert.spy(callback).was_called()
end)

it("Validates that run does not break if a exception on the callback", function()
Copy link
Contributor

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?

@@ -0,0 +1,78 @@
describe("Synchronization", function()
Copy link
Contributor

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.

@eloycoto eloycoto force-pushed the Issue-1010 branch 2 times, most recently from b1a881d to 89cfb7c Compare June 6, 2019 09:58
@eloycoto eloycoto force-pushed the Issue-1010 branch 2 times, most recently from 8cbde7f to 2c03d0c Compare June 6, 2019 11:03
eloycoto added 3 commits June 6, 2019 13:09
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>
@davidor davidor merged commit d797002 into 3scale:master Jun 6, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Ensure lock is released in the ConfigurationLoader module
2 participants