摘自:http://www.daileinote.com/computer/openresty/13

定时器一旦创建,就会脱离当前请求,也就是说就算当前请求结束了,定时器还是在的,它的生命周期跟创建它的 worker 进程一样。

ngx.timer.at

1
syntax: hdl, err = ngx.timer.at(delay, callback, user_arg1, user_arg2, ...)

创建定时器,到期时会回调 callback 函数。

delay 参数指定到期时间,单位为秒,精度0.001,代表1ms,也可以指定0,会立马过期并执行回调函数。

callback 回调函数第一个参数为 premature,接下来才是 user_arg1,user_arg2...,premature是个布尔值,代表是否是正常回调。

premature 为真的情况比如,nginx 准备关闭或者reload。

当定时器到期,回调函数以协程的方式运行,完全脱离创建该定时器的环境,对象生命周期跟创建它的worker进程一样,跟 cosockets 一样不能在原始环境和定时器回调函数里共享。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
location / {
...
log_by_lua_block {
local function push_data(premature, uri, args, status)
-- push the data uri, args, and status to the remote
-- via ngx.socket.tcp or ngx.socket.udp
-- (one may want to buffer the data in Lua a bit to
-- save I/O operations)
end
local ok, err = ngx.timer.at(0, push_data,
ngx.var.uri, ngx.var.args, ngx.header.status)
if not ok then
ngx.log(ngx.ERR, "failed to create timer: ", err)
return
end
}
}

也可以循环调用,例如每5s触发一次,当然不推荐这样用,应该用 ngx.timer.every 函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
local delay = 5
local handler
handler = function (premature)
-- 每5秒执行一次
if premature then
return
end
local ok, err = ngx.timer.at(delay, handler)
if not ok then
ngx.log(ngx.ERR, "failed to create the timer: ", err)
return
end
end

local ok, err = ngx.timer.at(delay, handler)
if not ok then
ngx.log(ngx.ERR, "failed to create the timer: ", err)
return
end

由于定时器是在后台运行的,可能由于一些错误会耗尽系统资源,所以每个 worker 进程都会有对 未过期的定时器和正在执行的定时器数量的限制,由 lua_max_pending_timers directive,lua_max_running_timers 两个指令设置。

一个正在运行的定时器会耗掉一个连接记录,由 worker_connections 设置,所以得保证 worker_connections 够大。

在定时器回调函数里,ngx.socket.tcp、ngx.socket.udp、ngx.shared.DICT、coroutine.*、ngx.thread.*、ngx.exit、ngx.now/ngx.time、ngx.md5/ngx.sha1_bin都是允许的,但是子请求Api比如 ngx.location.capture、ngx.req.*、ngx.say/ngx.print/ngx.flush都是不允许出现的。

回调函数不允许传递 coroutine 对象,cosocket 对象。

ngx.timer.every

1
syntax: hdl, err = ngx.timer.every(delay, callback, user_arg1, user_arg2, ...)

类似 ngx.timer.at,只是delay不能为0,每过 delay 时间就会调用回调函数直到worker进程终止。

成功 hdl 条件为真,失败 hdl 条件为假,但是 hdl不是布尔值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
server {
location /tcp {
content_by_lua_block {
function test(premature, a, b)
if pre then
ngx.log(ngx.ERR, "end")
return
end
ngx.log(ngx.ERR, a,b)
end
local h,err = ngx.timer.every(5, test, 1,2)
if h then
ngx.say("yes")
else
ngx.say("no")
end
}
}

}

这样每过5秒就会有日志记录到 logs/error.log,当 openresty reload 时,调用test回调设置 premature 为真。

ngx.timer.running_count

1
syntax: count = ngx.timer.running_count()

返回当前正在运行的定时器数量。

ngx.timer.pending_count

1
syntax: count = ngx.timer.pending_count()

返回当前没有到期的定时器数量。