Skip to content

Commit

Permalink
Add pause/resume feature for hotreloading (#1784)
Browse files Browse the repository at this point in the history
Co-authored-by: Igor Zolotarev <[email protected]>
  • Loading branch information
filonenko-mikhail and yngvar-antonsson authored Mar 31, 2022
1 parent a975f43 commit 53f3a57
Show file tree
Hide file tree
Showing 3 changed files with 99 additions and 0 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ Added

- Allow to pause failover at runtime, with Lua API and GraphQL (#1763).

- Allow to block roles reload at runtime, with Lua API (#1219).

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Changed
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Expand Down
45 changes: 45 additions & 0 deletions cartridge/roles.lua
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ vars:new('roles_by_number', {})
vars:new('roles_by_role_name', {})
vars:new('roles_by_module_name', {})
vars:new('implicit_roles')
vars:new('pause', false)

-- Don't put it as default var value to allow overriding
-- after hot-reload (hypothetically)
Expand Down Expand Up @@ -541,6 +542,8 @@ end
-- usual with `validate_config()`, `init()`, and `apply_config()`
-- callbacks.
--
-- Hot-reload could be forbidden in runtime with `forbid_reload` function.
--
-- @function reload
-- @treturn[1] boolean true
-- @treturn[2] nil
Expand All @@ -552,6 +555,12 @@ local function reload()
)
end

if vars.pause == true then
return nil, ReloadError:new(
'Reloading roles forbidden'
)
end

local confapplier = require('cartridge.confapplier')
local state = confapplier.get_state()
if state ~= 'RolesConfigured'
Expand Down Expand Up @@ -595,6 +604,38 @@ local function reload()
return confapplier.apply_config(clusterwide_config)
end

--- Forbid hot-reload of cartridge roles code.
--
-- @function forbid_reload
-- @treturn[1] boolean true
-- @treturn[2] nil
-- @treturn[2] table Error description
local function forbid_reload()
log.info('Forbid reload roles')
vars.pause = true
end

--- Allow hot-reload of cartridge roles code.
--
-- @function allow_reload
-- @treturn[1] boolean true
-- @treturn[2] nil
-- @treturn[2] table Error description
local function allow_reload()
log.info('Allow reload roles')
vars.pause = false
end

--- Returns true if hot-reload of cartridge roles code is forbidden.
--
-- @function is_reload_forbidden
-- @treturn[1] boolean true
-- @treturn[2] nil
-- @treturn[2] table Error description
local function is_reload_forbidden()
return vars.pause == true
end

return {
cfg = cfg,
get_role = get_role,
Expand All @@ -608,4 +649,8 @@ return {
apply_config = apply_config,
reload = reload,
stop = stop,

forbid_reload = forbid_reload,
allow_reload = allow_reload,
is_reload_forbidden = is_reload_forbidden,
}
52 changes: 52 additions & 0 deletions test/hotreload/pause_test.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
local fio = require('fio')
local t = require('luatest')
local g = t.group()

local helpers = require('test.helper')

g.before_all(function()
g.cluster = helpers.Cluster:new({
datadir = fio.tempdir(),
use_vshard = false,
server_command = helpers.entrypoint('srv_basic'),
cookie = helpers.random_cookie(),
replicasets = {{alias = 'A', roles = {}, servers = 1}},
})
g.cluster:start()
end)

g.after_all(function()
g.cluster:stop()
fio.rmtree(g.cluster.datadir)
end)

function g.test_errors()
local _ = g.cluster.main_server:exec(function()
package.loaded['cartridge.roles'].forbid_reload()
end)

local ok = g.cluster.main_server:exec(function()
return package.loaded['cartridge.roles'].is_reload_forbidden()
end)
t.assert_equals(ok, true)

local ok, err = g.cluster.main_server.net_box:call(
'package.loaded.cartridge.reload_roles'
)

t.assert_equals(ok, nil)
t.assert_covers(err, {
class_name = 'HotReloadError',
err = 'Reloading roles forbidden',
})

local _ = g.cluster.main_server:exec(function()
package.loaded['cartridge.roles'].allow_reload()
end)

local ok, err = g.cluster.main_server.net_box:call(
'package.loaded.cartridge.reload_roles'
)
t.assert_equals(ok, true)
t.assert_equals(err, nil)
end

0 comments on commit 53f3a57

Please sign in to comment.