Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions apisix/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,8 @@ function _M.http_init_worker()
load_balancer = require("apisix.balancer").run
require("apisix.admin.init").init_worker()

require("apisix.timers").init_worker()

router.http_init_worker()
require("apisix.http.service").init_worker()
plugin.init_worker()
Expand Down
24 changes: 23 additions & 1 deletion apisix/plugin.lua
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,26 @@ local function sort_plugin(l, r)
end


local function load_plugin(name, plugins_list, is_stream_plugin)
local function unload_plugin(name, is_stream_plugin)
local pkg_name = "apisix.plugins." .. name
if is_stream_plugin then
pkg_name = "apisix.stream.plugins." .. name
end

local old_plugin = pkg_loaded[pkg_name]
if old_plugin and type(old_plugin.destory) == "function" then
old_plugin.destory()
end

pkg_loaded[pkg_name] = nil
end


local function load_plugin(name, plugins_list, is_stream_plugin)
local pkg_name = "apisix.plugins." .. name
if is_stream_plugin then
pkg_name = "apisix.stream.plugins." .. name
end

local ok, plugin = pcall(require, pkg_name)
if not ok then
Expand Down Expand Up @@ -115,6 +129,10 @@ local function load(plugin_names)

core.log.warn("new plugins: ", core.json.delay_encode(processed))

for name in pairs(local_plugins_hash) do
unload_plugin(name)
end

core.table.clear(local_plugins)
core.table.clear(local_plugins_hash)

Expand Down Expand Up @@ -159,6 +177,10 @@ local function load_stream(plugin_names)

core.log.warn("new plugins: ", core.json.delay_encode(processed))

for name in pairs(stream_local_plugins_hash) do
unload_plugin(name, true)
end

core.table.clear(stream_local_plugins)
core.table.clear(stream_local_plugins_hash)

Expand Down
10 changes: 10 additions & 0 deletions apisix/plugins/example-plugin.lua
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,16 @@ function _M.check_schema(conf)
end


function _M.init()
-- call this function when plugin is loaded
end


function _M.destory()
-- call this function when plugin is unloaded
end


function _M.rewrite(conf, ctx)
core.log.warn("plugin rewrite phase, conf: ", core.json.encode(conf))
-- core.log.warn(" ctx: ", core.json.encode(ctx, true))
Expand Down
21 changes: 5 additions & 16 deletions apisix/plugins/log-rotate.lua
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
--

local core = require("apisix.core")
local timers = require("apisix.timers")
local process = require("ngx.process")
local signal = require("resty.signal")
local ngx = ngx
Expand All @@ -27,7 +28,6 @@ local string = string
local local_conf


local timer
local plugin_name = "log-rotate"
local INTERVAL = 60 * 60 -- rotate interval (unit: second)
local MAX_KEPT = 24 * 7 -- max number of log files will be kept
Expand Down Expand Up @@ -205,23 +205,12 @@ end


function _M.init()
core.log.info("enter log-rotate plugin, process type: ", process.type())

if process.type() ~= "privileged agent" and process.type() ~= "single" then
return
end
timers.register_timer("plugin#log-rotate", rotate, true)
end

if timer then
return
end

local err
timer, err = core.timer.new("logrotate", rotate, {check_interval = 0.5})
if not timer then
core.log.error("failed to create timer log rotate: ", err)
else
core.log.notice("succeed to create timer: log rotate")
end
function _M.destory()
timers.unregister_timer("plugin#log-rotate", true)
end


Expand Down
88 changes: 88 additions & 0 deletions apisix/timers.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
--
-- Licensed to the Apache Software Foundation (ASF) under one or more
-- contributor license agreements. See the NOTICE file distributed with
-- this work for additional information regarding copyright ownership.
-- The ASF licenses this file to You under the Apache License, Version 2.0
-- (the "License"); you may not use this file except in compliance with
-- the License. You may obtain a copy of the License at
--
-- http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.
--
local core = require("apisix.core")
local process = require("ngx.process")
local pairs = pairs
local unpack = unpack
local thread_spawn = ngx.thread.spawn
local thread_wait = ngx.thread.wait


local timers = {}


local _M = {}


local function background_timer()
local threads = {}
for name, timer in pairs(timers) do
core.log.info("run timer[", name, "]")

local th, err = thread_spawn(timer)
if not th then
core.log.error("failed to spawn thread for timer [", name, "]: ", err)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Should we use 'continue' here,since it's empty?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

@nic-chen
Updated.

goto continue
end

core.table.insert(threads, th)

::continue::
end

local ok, err = thread_wait(unpack(threads))
if not ok then
core.log.error("failed to wait threads: ", err)
end
end


local function is_privileged()
return process.type() == "privileged agent" or process.type() == "single"
end


function _M.init_worker()
local timer, err = core.timer.new("background", background_timer, {check_interval = 0.5})
if not timer then
core.log.error("failed to create background timer: ", err)
return
end

core.log.notice("succeed to create background timer")
end


function _M.register_timer(name, f, privileged)
if privileged and not is_privileged() then
return
end

timers[name] = f
end


function _M.unregister_timer(name, privileged)
if privileged and not is_privileged() then
return
end

timers[name] = nil
end


return _M
94 changes: 86 additions & 8 deletions t/plugin/log-rotate.t
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ add_block_preprocessor(sub {
my $user_yaml_config = <<_EOC_;
apisix:
node_listen: 1984
admin_key: null

plugins: # plugin list
- log-rotate
Expand All @@ -39,6 +40,7 @@ plugin_attr:
_EOC_

$block->set_value("yaml_config", $user_yaml_config);
$block->set_value("request", "GET /t");
});

run_tests;
Expand All @@ -64,21 +66,19 @@ __DATA__
local content = f:read("*all")
f:close()
local index = string.find(content, "start xxxxxx")
if index then
if index then
has_split_error_file = true
end
end
end
if not has_split_error_file or not has_split_error_file then

if not has_split_error_file or not has_split_error_file then
ngx.status = 500
else
ngx.status = 200
end
end
}
}
--- request
GET /t
--- error_code eval
[200]
--- no_error_log
Expand All @@ -95,11 +95,89 @@ GET /t
ngx.say("done")
}
}
--- request
GET /t
--- response_body
done
--- no_error_log
[error]
--- error_log
start xxxxxx



=== TEST 3: fix: ensure only one timer is running
--- config
location /t {
content_by_lua_block {
ngx.sleep(0.5)
local t = require("lib.test_admin").test
local code, _, org_body = t('/apisix/admin/plugins/reload',
ngx.HTTP_PUT)
Comment thread
membphis marked this conversation as resolved.

ngx.status = code
ngx.say(org_body)

ngx.sleep(1)

local lfs = require("lfs")
for file_name in lfs.dir(ngx.config.prefix() .. "/logs/") do
if string.match(file_name, "__error.log$") then
local f = assert(io.open(ngx.config.prefix() .. "/logs/" .. file_name, "r"))
local content = f:read("*all")
f:close()
local counter = 0
ngx.re.gsub(content, [=[run timer\[plugin#log-rotate\]]=], function()
counter = counter + 1
return ""
end)

if counter ~= 1 then
ngx.say("not a single rotater run at the same time: ", file_name)
end
end
end
}
}
--- response_body
done
--- no_error_log
[error]



=== TEST 4: disable log-rotate via hot reload
--- config
location /t {
content_by_lua_block {
local data = [[
apisix:
node_listen: 1984
admin_key: null
plugins:
- prometheus
]]
require("lib.test_admin").set_config_yaml(data)
local t = require("lib.test_admin").test
local code, _, org_body = t('/apisix/admin/plugins/reload',
ngx.HTTP_PUT)
Comment thread
membphis marked this conversation as resolved.

ngx.status = code
ngx.say(org_body)

ngx.sleep(1.5)

local n_split_error_file = 0
local lfs = require("lfs")
for file_name in lfs.dir(ngx.config.prefix() .. "/logs/") do
if string.match(file_name, "__error.log$") then
n_split_error_file = n_split_error_file + 1
end
end

ngx.say(n_split_error_file)
}
}
--- response_body
done
1
--- no_error_log
[error]