-
Notifications
You must be signed in to change notification settings - Fork 4.8k
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
fix(balancer) async initialization of balancer objects #3187
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,7 +8,11 @@ local table_concat = table.concat | |
local crc32 = ngx.crc32_short | ||
local toip = dns_client.toip | ||
local log = ngx.log | ||
local sleep = ngx.sleep | ||
local min = math.min | ||
local max = math.max | ||
|
||
local CRIT = ngx.CRIT | ||
local ERR = ngx.ERR | ||
local WARN = ngx.WARN | ||
local DEBUG = ngx.DEBUG | ||
|
@@ -289,9 +293,49 @@ do | |
end | ||
end | ||
|
||
local creating = {} | ||
|
||
local function wait(id) | ||
local timeout = 30 | ||
local step = 0.001 | ||
local ratio = 2 | ||
local max_step = 0.5 | ||
while timeout > 0 do | ||
sleep(step) | ||
timeout = timeout - step | ||
if not creating[id] then | ||
return true | ||
end | ||
if timeout <= 0 then | ||
break | ||
end | ||
step = min(max(0.001, step * ratio), timeout, max_step) | ||
end | ||
return nil, "timeout" | ||
end | ||
|
||
------------------------------------------------------------------------------ | ||
-- @param upstream (table) The upstream data | ||
-- @param recreate (boolean, optional) create new balancer even if one exists | ||
-- @param history (table, optional) history of target updates | ||
-- @param start (integer, optional) from where to start reading the history | ||
-- @return The new balancer object, or nil+error | ||
create_balancer = function(upstream, history, start) | ||
create_balancer = function(upstream, recreate, history, start) | ||
|
||
if balancers[upstream.id] and not recreate then | ||
return balancers[upstream.id] | ||
end | ||
|
||
if creating[upstream.id] then | ||
local ok = wait(upstream.id) | ||
if not ok then | ||
return nil, "timeout waiting for balancer for " .. upstream.id | ||
end | ||
return balancers[upstream.id] | ||
end | ||
|
||
creating[upstream.id] = true | ||
|
||
local balancer, err = ring_balancer.new({ | ||
wheelSize = upstream.slots, | ||
order = upstream.orderlist, | ||
|
@@ -319,6 +363,8 @@ do | |
-- is fully set up. | ||
balancers[upstream.id] = balancer | ||
|
||
creating[upstream.id] = nil | ||
|
||
return balancer | ||
end | ||
end | ||
|
@@ -374,7 +420,7 @@ local function check_target_history(upstream, balancer) | |
|
||
stop_healthchecker(balancer) | ||
|
||
local new_balancer, err = create_balancer(upstream, new_history, 1) | ||
local new_balancer, err = create_balancer(upstream, true, new_history, 1) | ||
if not new_balancer then | ||
return nil, err | ||
end | ||
|
@@ -470,7 +516,7 @@ local function get_balancer(target, no_create) | |
return nil, "balancer not found" | ||
else | ||
log(ERR, "balancer not found for ", upstream.name, ", will create it") | ||
return create_balancer(upstream) | ||
return create_balancer(upstream), upstream | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. dammit, seems like this already was an issue? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. it wasn't -- I mean, it was with regard to the function signature but it didn't happen because the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. My one concern here is that this can be confusing for users of get_balancer and increase cognitive load: local balancer, err = create_balancer(upstream)
if not balancer then
return nil, err
end
return balancer, upstream -- still somewhat annoying to me, I prefer `balancer, nil, upstream` but up to you! |
||
end | ||
end | ||
|
||
|
@@ -523,7 +569,7 @@ local function on_upstream_event(operation, upstream) | |
|
||
local _, err = create_balancer(upstream) | ||
if err then | ||
log(ERR, "failed creating balancer for ", upstream.name, ": ", err) | ||
log(CRIT, "failed creating balancer for ", upstream.name, ": ", err) | ||
end | ||
|
||
elseif operation == "delete" or operation == "update" then | ||
|
@@ -540,7 +586,7 @@ local function on_upstream_event(operation, upstream) | |
if operation == "delete" then | ||
balancers[upstream.id] = nil | ||
else | ||
local _, err = create_balancer(upstream) | ||
local _, err = create_balancer(upstream, true) | ||
if err then | ||
log(ERR, "failed recreating balancer for ", upstream.name, ": ", err) | ||
end | ||
|
@@ -603,9 +649,10 @@ end | |
|
||
|
||
local function init() | ||
|
||
local upstreams, err = get_all_upstreams() | ||
if not upstreams then | ||
log(ngx.STDERR, "failed loading initial list of upstreams: ", err) | ||
log(CRIT, "failed loading initial list of upstreams: " .. err) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Minor, but better not make use of Lua-land string concatenation in those error messages, and rely on the variadic arguments of |
||
return | ||
end | ||
|
||
|
@@ -616,11 +663,12 @@ local function init() | |
if ok ~= nil then | ||
oks = oks + 1 | ||
else | ||
log(ngx.STDERR, "failed creating balancer for ", name, ": ", err) | ||
log(CRIT, "failed creating balancer for ", name, ": ", err) | ||
errs = errs + 1 | ||
end | ||
end | ||
log(DEBUG, "initialized ", oks, " balancer(s), ", errs, " error(s)") | ||
|
||
end | ||
|
||
|
||
|
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.
should we scope this and other
create_balancer
dependencies under ado ... end
block? It'd be a little bit saner/easier to skim through imhoThere 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 is already inside a do-block and far down so it's only visible to the two relevant functions that need it. Can we leave this one as-is?
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.
Hmm I missed it; quite large for
do
block, but that's fine!