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对象)。因此,应该在定时器回调函数中创建这些对象。