一、主要作用:
通过在后台启用nginx轻线程在指定的延时后,调用指定的函数,可以实现类似于javascript中的setTimeout和setInterval类似的功能。
注意:
- 有些ngx_lua中的API不能在timer中调用,因为timer是与任何请求无关的,因此,比如子请求、ngx.req.*和向下游输出的API(如ngx.print,ngx.flush等)不能在timer中使用。
二、主要指令
这两个指令决定了定时器最大运行数量和等待数量
- 1、lua_max_running_timers
指定最大运行的定时器数量(默认值为256)
- 2、lua_max_pending_timers
指定最大等待运行的定时器的数量(默认值为1024)
三、主要API
1、ngx.timer.at
用法:
ok,err = ngx.timer(delay, callback, arg1, arg2,...)
参数:
- delay表示延迟的时间,以秒为单位(可以使用小数)
- callback表示延迟后执行的函数
- arg1,arg2,…表示传入callback的参数
- callback的定义如下:
local handler
handler = function(premature)
//要执行的功能代码
end
注:
- premature这个参数不是调用ngx.timer.at传入的参数,它是一个固定的参数,表示定时器是否过期
- 作用:在指定的延迟时间(delay)后,执行callback这个函数
例如:
在5秒后,将字符串”create timer success”记录到日志中
local ok,err = ngx.timer.at(5, function()
ngx.log(ngx.ERR, 'create timer success')
end)
2、ngx.timer.running_count
用法:count = ngx.timer.running_count()
作用:获取正在运行的定时器的数量
3、ngx.timer.pending_count
用法:count = ngx.timer.pending_count()
作用:获取正在等待的定时器的数量
四、通过ngx.timer.at来实现定时任务
在openresty中一般使用init_worker_by_lua*指令与ngx.timer.at来配合使用实现定时任务
注:
- init_worker_by_lua*指令会在每个woker初始化时执行,因此在有多个worker的情况下,得判断worker的ID,让指定的worker来执行某个定时任务,以防止重复执行
- ngx.timer.at只会执行一次,它的功能类似于javascript的setTimeout函数,因此要实现定时任务,需要嵌套使用ngx.timer.at
1、在每隔X秒执行一个函数
实现类似于javascript中的setInterval的功能
local delay = 5
local handler
handler = function(premature)
if not premature then
ngx.log(ngx.ERR, os.date("%Y-%m-%d %H:%M:%S", ngx.time()).." : create timer success")
local ok,err = ngx.timer.at(delay, handler)
if not ok then
ngx.log(ngx.ERR, "failed to create the timer:", err)
end
end
end
if ngx.worker.id() == 1 then
local ok,err = ngx.timer.at(delay, handler)
if not ok then
ngx.log(ngx.ERR, "failed to create the timer:", err)
end
end
重启nginx,我们查看nginx的错误日志:
2、实现在某个固定时间执行一个函数
类现类似于Linux的crontab的功能
- 原理:每次在触发定时器函数时判断当前时间与执行时间是否一致,如果一致,则执行功能代码。(这里要注意的是定时器延迟时间的粒度问题,要考虑固定时间的时间点的粒度与延迟时间的粒度,比如这个定时器是每5秒执行一次,如果这个定时任务,精确到秒,那么需要注意是否可以满足其精确度)
例如:在每天的02:00时向日志输入一条信息
local delay = 5 -- 延迟时间
local interval_time = '0200' -- 执行任务的时间点,格式可以随意,如02:00
local handler
handler = function(premature, interval_time)
if not premature then
local nowtime = os.date("%H%M")
if nowtime == interval_time then
ngx.log(ngx.ERR, ngx.today().." : create interval task success")
-- 这是要修改interval_time的时间点,不然会在每隔5秒又重复执行
interval_time = tostring(tonumber(interval_time) - 1)
end
local ok, err = ngx.timer.at(delay, handler, interval_time)
if not ok then
ngx.log(ngx.ERR, "failed to create the timer:", err)
return
end
end
end
if ngx.worker.id() == 1 then
local ok, err = ngx.timer.at(delay, handler, interval_time)
if not ok then
ngx.log(ngx.ERR, "failed to create the timer:", err)
return
end
end