openresty - lua API(8) - 定时器 - ngx.timer

2018-08-02 22:32:46

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

ngx.timer.at

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 一样不能在原始环境和定时器回调函数里共享。

 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 函数。

 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

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

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

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

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

syntax: count = ngx.timer.running_count()

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

ngx.timer.pending_count

syntax: count = ngx.timer.pending_count()

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


备注

1.测试环境centos7 64位,openresty 版本为 1.13.6.2。
2..原文地址http://www.freecls.com/a/2712/f6


©著作权归作者所有
收藏
推荐阅读
简介
天降大任于斯人也,必先苦其心志。