ok, err = ngx.timer.at(delay, callback, user_arg1, user_arg2, ...)
init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.*, balancer_by_lua*, ssl_certificate_by_lua*
使用用户自定义的回调函数以及可选的自定义参数创建一个Nginx定时器。
第一个参数delay用于指定定时器的延迟,单位是秒。可以将其指定为小数,比如0.001代表1毫秒,也可以将delay指定为0,在这种情况下,当当前的handler执行的时候,定时器会立即到期(可以理解为:立即执行用户自定义的回调函数)。
第二个参数callback可以是任何Lua函数,在指定的延迟之后,这个回调函数会在后台的“轻量级线程”中被调用。用户自定义的回调函数会自动的被Nginx核心使用premature,user_arg1,user_arg2等参数调用。premature是一个布尔值,代表定时器是否是提前到期的。user_arg1,user_arg2等参数是在调用ngx.timer.at的时候指定的用户自定义参数。
当Nginx worker进程尝试关闭的时候,定时器会提前到期。比如:通过HUP信号触发的配置文件重载,或者是关闭Nginx。当Nginx Worker尝试关闭的时候,不能再使用非0的延迟调用ngx.timer.at创建新的定时器。在这种情形下,ngx.timer.at会返回nil和一个描述错误信息的字符串("process exiting")。
从v0.9.3版本开始,即使Nginx worker进程开始关闭,也允许创建0延迟计时器。
当一个定时器到期的时候,定时器回调函数中的Lua代码会在后台的“轻量级线程”中执行。它与创建定时器的原始请求是完全分离的。因此与创建定时器的请求具有相同生命周期的对象,比如cosockets,是不能在原始的请求和定时器回调函数中共享的。
下面是一个简单的例子:
location / {
...
log_by_lua '
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
';
}
也可以创建无限重复执行的定时器。比如,通过在计时器的回调函数中,递归地调用ngx.timer.at,实现每5秒触发一次的定时器。下面是一个简单的例子:
local delay = 5
local handler
handler = function (premature)
-- do some routine job in Lua just like a cron job
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
因为定时器回调函数是在后台运行的,他们的运行时间没有添加到任何客户端请求的响应时间中,因此,定时器很容易在服务器内部堆积,消耗系统资源。
为了阻止某些极端的后果,比如Nginx服务器崩溃,在Nginx worker进程内,对挂起的定时器的数量和正在运行的定时器的数量都有限制。挂起的定时器就是还没有到期的定时器,正在运行的定时器是指回调函数正在运行的定时器。
挂起的定时器的最大数量是由lua_max_pending_timers指令控制的,正在运行的定时器的最大数量是由lua_max_running_timers指令控制的。
当前的实现是:每个正在运行的定时器都会从全局的连接记录列表(在nginx.conf中通过worker_connections指定配置的)中消耗一个连接(本质上是一个伪连接)。因此确保worker_connections指令被设置为一个足够大的值,以便能够同时处理真正的连接和定时器回调函数需要的伪连接。
许多Nginx的Lua API都可以在定时器中使用,比如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.* API,downstream输出API,比如ngx.say,ngx.print,ngx.flush是无法使用的。
可以显式的使用用户自定义参数或隐式的使用闭包,传递大多数的Lua值(nils,booleans,numbers,strings,tables,closures,file handles等)给定时器回调函数。不能传递给定时器回调函数的对象包括:coroutine.create和ngx.thread.spawn返回的任何线程对象,ngx.socket.tcp,ngx.socket.udp,ngx.req.socket返回的任何cosocket对象,因为这些对象的生命周期被绑定到了创建它们的请求上下文中,而定时器回调函数与创建请求的上下文是完全分离的,它运行在自己的伪请求上下文中。如果企图共享这类对象的话,会报错no co ctx found(thread对象)或bad request(cosocket对象)。因此,应该在定时器回调函数中创建这些对象。