Skip to content

Commit cc97625

Browse files
committed
fix(plugin_iterator) guard against Lua error that happens inside plugin's "init_worker" handler
Previously when a plugin's "init_worker" handler fails, the rest of the `init_worker` task are no longer executed. Although this is not something that should happen in normal situation, there are certain custom plugins that are not written correctly and failed "init_worker" causes things like Hybrid mode to break because it's `init_worker` code no longer executes. This PR allows the Kong node to finish the rest of the initialization even in case of plugin's "init_worker" handler error. It should improve the situation because Kong core's initialization generally does not depend on the outcome of a particular plugin's "init_worker" handler, and this improves the stability of the product slightly. Because failed "init_worker" handler is still considered a serious event, we use the `stash_init_worker_error` function so the error message will be printed for each incoming request later. This is the same behavior as we do for the other initialization failures that could occur in core.
1 parent e0f83b7 commit cc97625

File tree

4 files changed

+55
-2
lines changed

4 files changed

+55
-2
lines changed

kong/init.lua

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,7 @@ end
243243
local function execute_plugins_iterator(plugins_iterator, phase, ctx)
244244
local old_ws
245245
local delay_response
246+
local errors
246247

247248
if ctx then
248249
old_ws = ctx.workspace
@@ -262,7 +263,21 @@ local function execute_plugins_iterator(plugins_iterator, phase, ctx)
262263
kong_global.set_namespaced_log(kong, plugin.name)
263264

264265
if not delay_response then
265-
plugin.handler[phase](plugin.handler, configuration)
266+
-- guard against failed handler in "init_worker" phase only because it will
267+
-- cause Kong to not correctly initialize and can not be recovered automatically.
268+
if phase == "init_worker" then
269+
local ok, err = pcall(plugin.handler[phase], plugin.handler, configuration)
270+
if not ok then
271+
errors = errors or {}
272+
errors[#errors + 1] = {
273+
plugin = plugin.name,
274+
err = err,
275+
}
276+
end
277+
278+
else
279+
plugin.handler[phase](plugin.handler, configuration)
280+
end
266281

267282
elseif not ctx.delayed_response then
268283
local co = coroutine.create(plugin.handler.access)
@@ -282,6 +297,8 @@ local function execute_plugins_iterator(plugins_iterator, phase, ctx)
282297
ctx.workspace = old_ws
283298
end
284299
end
300+
301+
return errors
285302
end
286303

287304

@@ -616,7 +633,14 @@ function Kong.init_worker()
616633
end
617634

618635
local plugins_iterator = runloop.get_plugins_iterator()
619-
execute_plugins_iterator(plugins_iterator, "init_worker")
636+
local errors = execute_plugins_iterator(plugins_iterator, "init_worker")
637+
if errors then
638+
for _, e in ipairs(errors) do
639+
local err = "failed to execute the \"init_worker\" " ..
640+
"handler for plugin \"" .. e.plugin .."\": " .. e.err
641+
stash_init_worker_error(err)
642+
end
643+
end
620644

621645
runloop.init_worker.after()
622646

spec/02-integration/05-proxy/04-plugins_triggering_spec.lua

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ local pl_stringx = require "pl.stringx"
77

88

99
local LOG_WAIT_TIMEOUT = 10
10+
local TEST_CONF = helpers.test_conf
1011

1112

1213
for _, strategy in helpers.each_strategy() do
@@ -1089,6 +1090,7 @@ for _, strategy in helpers.each_strategy() do
10891090
assert(helpers.start_kong {
10901091
database = strategy,
10911092
nginx_conf = "spec/fixtures/custom_nginx.template",
1093+
plugins = "short-circuit,init-worker-lua-error",
10921094
})
10931095

10941096
proxy_client = helpers.proxy_client()
@@ -1119,6 +1121,11 @@ for _, strategy in helpers.each_strategy() do
11191121
message = "plugin executed"
11201122
}, json)
11211123
end)
1124+
1125+
it("protects against failed init_worker handler, FTI-2473", function()
1126+
local logs = pl_file.read(TEST_CONF.prefix .. "/" .. TEST_CONF.proxy_error_log)
1127+
assert.matches([[worker initialization error: failed to execute the "init_worker" handler for plugin "init-worker-lua-error"]], logs, nil, true)
1128+
end)
11221129
end)
11231130

11241131
if strategy ~= "off" then
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
local InitWorkerLuaError = {}
2+
3+
4+
InitWorkerLuaError.PRIORITY = 1000
5+
6+
7+
function InitWorkerLuaError:init_worker(conf)
8+
error("this fails intentionally")
9+
end
10+
11+
12+
return InitWorkerLuaError
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
return {
2+
name = "init-worker-lua-error",
3+
fields = {
4+
{ config = {
5+
type = "record",
6+
fields = { },
7+
}
8+
}
9+
}
10+
}

0 commit comments

Comments
 (0)