语法格式:res, err = ngx.timer.every(delay, callback, arg, arg2, ...)
* 每隔delay秒执行一次,delay支持设置到0.001s,不支持设置为0s
* callback为回调函数,定时任务每次执行都会调用
* arg, arg2, ... 为传递给定时任务的参数
环境:init_worker_by_lua*、log_by_lua*、ngx.timer.*、balancer_by_lua*、
set_by_lua*、rewrite_by_lua*、content_by_lua*、access_by_lua*、
header_filter_by_lua*、body_filter_by_lua*、ssl_certificated_by_lua*、
ssl_session_fetch_by_lua*、ssl_session_store_by_lua*、ssl_client_hello_by_lua*
ngx.timer.at:周期性执行定时任务
语法格式:hdl, err = ngx.timer.at(delay, callback, arg, arg2, ...)
* delay=0时,表示立即执行任务,并且只执行一次
* delay不为0时,表示每隔delay秒执行一次任务
* callback为回调函数,定时任务每次执行都会调用
* arg, arg2, ... 表示传递给回调函数的参数
环境:init_worker_by_lua*、log_by_lua*、ngx.timer.*、balancer_by_lua*、
set_by_lua*、 rewrite_by_lua*、content_by_lua*、access_by_lua*、
header_filter_by_lua*、body_filter_by_lua*、ssl_certificate_by_lua*、
ssl_session_fetch_by_lua*、ssl_session_store_by_lua*、ssl_client_hello_by_lua
callback 函数说明
location / {
log_by_lua_block {
-- 回调函数:第一个参数premature,后续的参数都为创建定时任务传递的参数
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)
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
-- other job in log_by_lua_block
The user callback will be called automatically by the Nginx core with the
arguments premature, user_arg1, user_arg2, and etc, where the premature
argument takes a boolean value indicating whether it is a premature timer
expiration or not, and user_arg1, user_arg2, and etc, are those (extra) user
arguments specified when calling ngx.timer.at as the remaining arguments.
* 回调函数会自动调用,参数为premature, user_arg1, user_arg2等自定义参数
* premature是一个boolean值,表明定时任务是否过期
* ser_arg1, user_arg2等是用户自定义参数
Premature timer expiration happens when the Nginx worker process is trying to
shut down, as in an Nginx configuration reload triggered by the HUP signal or
in an Nginx server shutdown. When the Nginx worker is trying to shut down, one
can no longer call ngx.timer.at to create new timers with nonzero delays and in
that case ngx.timer.at will return a "conditional false" value and a string
describing the error, that is, "process exiting"
* worker关闭的时候(hup信号、shutdown),premature返回true
* premature返回true时,delay=0的定时任务也不会调用,
* 会返回字符串conditional false,err=process exiting
定时任务中禁用的api
子请求api:ngx.location.capture
输出api:ngx.say、ngx.print、ngx.flush
请求api:ngx.req.*(以ngx.req.开头的api)
lua_max_running_timers:限制最多运行的定时任务数量
语法格式:lua_max_running_timers count
* 限制最多同时运行的定时任务的数量
环境:http
When exceeding this limit, Nginx will stop running the callbacks of
newly expired timers and log an error message "N lua_max_running_timers
are not enough" where "N" is the current value of this directive
* 超过最大限制时,nginx会停止新的定时任务运行,
* 日志打印信息:N lua_max_running_timers are not enough
* N为设置的count值
lua_max_pending_timers:限制挂起的定时任务的数量
语法格式:lua_max_pending_timers count
* 限制最多挂起的定时任务的数量
环境:http
When exceeding this limit, the ngx.timer.at call will immediately
return nil and the error string "too many pending timers"
* 超过最大限制时,nginx会立刻返回nil,
* 返回错误信息:too many pending timers
default.conf
server {
listen 80;
server_name localhost;
location /test {
content_by_lua_block {
local callback = function(premature, arg)
if not premature then
ngx.log(ngx.ERR, " ngx.worker.id ==> ", ngx.worker.id(), " info ==>", arg)
if ngx.worker.id() == 0 then
ngx.say("gtlx");
local res, err = ngx.timer.every(3, callback, "gtlx")
if not res then
ngx.log(ngx.ERR, " 定时任务执行失败 ==> ", err)
return
ngx.say("test")
#error_page 404 /404.html;
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/local/openresty/nginx/html;
docker run -it -d -p 2004:80 \
-v /Users/huli/lua/openresty/conf8/default.conf:/etc/nginx/conf.d/default.conf \
--name open8 lihu12344/openresty
huli@hudeMacBook-Pro conf8 % curl localhost:2004/test
查看日志:每隔3秒输出一次日志
huli@hudeMacBook-Pro conf8 % docker logs -f open8
172.17.0.1 - - [10/Jul/2022:08:05:14 +0000] "GET /test HTTP/1.1" 200 25 "-" "curl/7.77.0"
2022/07/10 08:05:18 [error] 8#8: *2 [lua] content_by_lua(default.conf:24):4: ngx.worker.id ==> 0 info ==>gtlx, context: ngx.timer, client: 172.17.0.1, server: 0.0.0.0:80
huli@hudeMacBook-Pro conf8 % docker logs -f open8
172.17.0.1 - - [10/Jul/2022:08:05:14 +0000] "GET /test HTTP/1.1" 200 25 "-" "curl/7.77.0"
2022/07/10 08:05:18 [error] 8#8: *2 [lua] content_by_lua(default.conf:24):4: ngx.worker.id ==> 0 info ==>gtlx, context: ngx.timer, client: 172.17.0.1, server: 0.0.0.0:80
2022/07/10 08:05:21 [error] 8#8: *3 [lua] content_by_lua(default.conf:24):4: ngx.worker.id ==> 0 info ==>gtlx, context: ngx.timer, client: 172.17.0.1, server: 0.0.0.0:80
2022/07/10 08:05:24 [error] 8#8: *4 [lua] content_by_lua(default.conf:24):4: ngx.worker.id ==> 0 info ==>gtlx, context: ngx.timer, client: 172.17.0.1, server: 0.0.0.0:80
2022/07/10 08:05:27 [error] 8#8: *5 [lua] content_by_lua(default.conf:24):4: ngx.worker.id ==> 0 info ==>gtlx, context: ngx.timer, client: 172.17.0.1, server: 0.0.0.0:80
2022/07/10 08:05:30 [error] 8#8: *6 [lua] content_by_lua(default.conf:24):4: ngx.worker.id ==> 0 info ==>gtlx, context: ngx.timer, client: 172.17.0.1, server: 0.0.0.0:80
2022/07/10 08:05:33 [error] 8#8: *7 [lua] content_by_lua(default.conf:24):4: ngx.worker.id ==> 0 info ==>gtlx, context: ngx.timer, client: 172.17.0.1, server: 0.0.0.0:80
2022/07/10 08:05:36 [error] 8#8: *8 [lua] content_by_lua(default.conf:24):4: ngx.worker.id ==> 0 info ==>gtlx, context: ngx.timer, client: 172.17.0.1, server: 0.0.0.0:80
2022/07/10 08:05:39 [error] 8#8: *9 [lua] content_by_lua(default.conf:24):4: ngx.worker.id ==> 0 info ==>gtlx, context: ngx.timer, client: 172.17.0.1, server: 0.0.0.0:80
2022/07/10 08:05:42 [error] 8#8: *10 [lua] content_by_lua(default.conf:24):4: ngx.worker.id ==> 0 info ==>gtlx, context: ngx.timer, client: 172.17.0.1, server: 0.0.0.0:80
这个Lua库是ngx_lua nginx模块的Redis客户端驱动程序:
这个Lua库利用了ngx_lua的cosocket API,可确保100%的非阻塞行为。
请注意,至少需要或 。
# you do not need the following line if you are using
# the OpenResty bundle:
lua_package_path " /path/to/lua-resty-redis/lib/?.lua;; " ;
server {
location / test {
content_by_lua_bloc
安装步骤可以参考
1.安装依赖,我的是centos,其他系统请参考上边链接里的说明
yum install readline-devel pcre-devel openssl-devel gcc
2.下载 openresty (可以下载最新的)
tar -xzvf ngx_openresty-1.7.7.2.tar.gz
ngx_openresty-1.7.7.2/bundle目录里存放着nginx核心和很多第三方模块,比如有我们需要的Lua和LuaJIT。
3.安装LuaJIT
cd bundle/LuaJIT-2.1-20150120/
make clean && make && make install
ln -sf luajit-2.
openresty的定时任务是要跟worker绑定的。如果不绑定特定的worker,那么所有启动的woker都会去执行定时任务。
一般情况下默认绑定worker_id=0的,这样在nginx整个进程里面,就只执行一个timer。
在conf中具体的位置可以写自己的任务逻辑。
十四、获取Nginx的环境变量
通过Lua API可以获取Nginx的环境变量,用来提升某些业务处理流程,比如有些定时任务只需要在一个worker进程上执行,不需要执行多次,因此可以获取环境变量中worker的ID,在指定的ID上执行任务即可;或者获取Nginx的worker进程是否正在shutdown,以决定是否对数据进行备份操作。
14.1 获取环境所在的模块ngx.config.subsys...
ngx.
timer.at语法示例执行一次
定时任务参考
hdl, err =
ngx.
timer.at(delay, callback, user_arg1, user_arg2, …)
创建用户自定义函数及参数的定时器
delay
表示延迟的时间,以秒为单位(可以使用小数),可以使用小数,精确到 0.001(1毫秒)
callback
用户自定义函数
代码片段.
// 自定义函数
local callbakcFun = function(premature, arg1,...)
tcpdump有收包,但是nginx的access.log显示post数据为空
可以通过tcpdump监控端口
http://www.cnblogs.com/linn/p/4792468.html
client_header_buffer_size 20k;
large_client_header_buffers 4 8k;
client_max_body...
local handler
-- do some routine job in
Lua just like a cron job
handler = function (premature)
ngx.log(
ngx.INFO,"====================
定时任务执行开始===================...
2)但是'服务器内部'需要'5/10s'给终端传输数据
原因: 定时器一旦创建,就会'脱离当前请求','也就是说'就算当前请求结束了,定时器还是在的,它的'生命周期'跟创建它的 'worker 进程'一样
++++++++++++'业务场景2'++++..
- ngx.DEBUG:调试级别
...是要打印的日志信息,可以是一个或多个参数。ngx.log()函数的调用需要在ngx.ctx上下文中进行。ngx.ctx是OpenResty中的一个特殊变量,它可以在请求处理过程中传递数据,并且在不同的处理阶段中保持不变。这使得我们可以在不同的处理阶段中打印同一个日志信息,从而更好地跟踪请求的处理过程。例如:
location / {
content_by_lua_block {
ngx.ctx.msg = "hello world"
ngx.log(ngx.INFO, "handle request")
ngx.exec("/foo")
location /foo {
content_by_lua_block {
ngx.log(ngx.INFO, "handle request, msg: ", ngx.ctx.msg)
ngx.exit(200)
在这个例子中,我们在第一个location中设置了ngx.ctx.msg变量,并在ngx.log()函数中打印了一个日志信息。然后,我们使用ngx.exec()函数将请求转发到另一个location中。在第二个location中,我们通过ngx.log()函数再次打印了一个日志信息,并将ngx.ctx.msg变量的值也输出了出来。由于ngx.ctx是在整个请求周期中保持不变的,所以在第二个location中我们可以直接访问到第一个location中设置的ngx.ctx.msg变量的值。