Skip to content

Commit 8981872

Browse files
kingluodoujiang24
authored and
doujiang24
committed
feature: implement the new ngx.run_worker_thread API to run Lua function in a seperated worker thread.
1 parent 263bd0c commit 8981872

11 files changed

+1493
-4
lines changed

README.markdown

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1162,6 +1162,7 @@ Directives
11621162
* [lua_max_pending_timers](#lua_max_pending_timers)
11631163
* [lua_max_running_timers](#lua_max_running_timers)
11641164
* [lua_sa_restart](#lua_sa_restart)
1165+
* [lua_worker_thread_vm_pool_size](#lua_worker_thread_vm_pool_size)
11651166

11661167

11671168
The basic building blocks of scripting Nginx with Lua are directives. Directives are used to specify when the user Lua code is run and
@@ -3328,6 +3329,25 @@ This directive was first introduced in the `v0.10.14` release.
33283329

33293330
[Back to TOC](#directives)
33303331

3332+
lua_worker_thread_vm_pool_size
3333+
------------------------------
3334+
3335+
**syntax:** *lua_worker_thread_vm_pool_size <size>*
3336+
3337+
**default:** *lua_worker_thread_vm_pool_size 100*
3338+
3339+
**context:** *http*
3340+
3341+
Specifies the size limit of the Lua VM pool (default 100) that will be used in the [ngx.run_worker_thread](#ngxrun_worker_thread) API.
3342+
3343+
Also, it is not allowed to create Lua VMs that exceeds the pool size limit.
3344+
3345+
The Lua VM in the VM pool is used to execute Lua code in seperate thread.
3346+
3347+
The pool is global at Nginx worker level. And it is used to reuse Lua VMs between requests.
3348+
3349+
[Back to TOC](#directives)
3350+
33313351
Nginx API for Lua
33323352
=================
33333353

@@ -3480,6 +3500,7 @@ Nginx API for Lua
34803500
* [coroutine.wrap](#coroutinewrap)
34813501
* [coroutine.running](#coroutinerunning)
34823502
* [coroutine.status](#coroutinestatus)
3503+
* [ngx.run_worker_thread](#ngxrun_worker_thread)
34833504

34843505

34853506
[Back to TOC](#table-of-contents)
@@ -8960,6 +8981,134 @@ This API was first enabled in the `v0.6.0` release.
89608981

89618982
[Back to TOC](#nginx-api-for-lua)
89628983

8984+
ngx.run_worker_thread
8985+
---------------------
8986+
8987+
**syntax:** *ok, res1, res2, ... = ngx.run_worker_thread(threadpool, module_name, func_name, arg1, arg2, ...)*
8988+
8989+
**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua**
8990+
8991+
**This API is still experimental and may change in the future without notice.**
8992+
8993+
**This API is available only for Linux.**
8994+
8995+
Wrap the [nginx worker thread](http://nginx.org/en/docs/dev/development_guide.html#threads) to execute lua function. The caller coroutine would yield until the function returns.
8996+
8997+
Note that no ngx_lua API can be used in the `function_name` function of the `module` module since it is invoked in a separate thread.
8998+
8999+
The first argument `threadpool` specifies the Nginx thread pool name defined by [thread_pool](https://nginx.org/en/docs/ngx_core_module.html#thread_pool).
9000+
9001+
The second argument `module_name` specifies the lua module name to execute in the worker thread, which would return a lua table. The module must be inside the package path, e.g.
9002+
9003+
```nginx
9004+
9005+
lua_package_path '/opt/openresty/?.lua;;';
9006+
```
9007+
9008+
The third argument `func_name` specifies the function field in the module table as the second argument.
9009+
9010+
The type of `arg`s must be one of type below:
9011+
9012+
* boolean
9013+
* number
9014+
* string
9015+
* nil
9016+
* table (the table may be recursive, and contains members of types above.)
9017+
9018+
The `ok` is in boolean type, which indicate the C land error (failed to get thread from thread pool, pcall the module function failed, .etc). If `ok` is `false`, the `res1` is the error string.
9019+
9020+
The return values (res1, ...) are returned by invocation of the module function. Normally, the `res1` should be in boolean type, so that the caller could inspect the error.
9021+
9022+
This API is useful when you need to execute the below types of tasks:
9023+
9024+
* CPU bound task, e.g. do md5 calculation
9025+
* File I/O task
9026+
* Call `os.execute()` or blocking C API via `ffi`
9027+
* Call external Lua library not based on cosocket or nginx
9028+
9029+
Example1: do md5 calculation.
9030+
9031+
```nginx
9032+
9033+
location /calc_md5 {
9034+
default_type 'text/plain';
9035+
9036+
content_by_lua_block {
9037+
local ok, ret, md5_or_err = ngx.run_worker_thread("testpool", "calc_md5", "md5", ngx.var.arg_str)
9038+
if not ok then
9039+
ngx.say(ret)
9040+
return
9041+
end
9042+
if not ret then
9043+
ngx.say(md5_or_err)
9044+
return
9045+
end
9046+
ngx.say(md5_or_err)
9047+
}
9048+
}
9049+
```
9050+
9051+
`calc_md5.lua`
9052+
9053+
```lua
9054+
9055+
local resty_md5 = require "resty.md5"
9056+
local resty_str = require "resty.string"
9057+
9058+
local function md5(str)
9059+
local md5 = resty_md5:new()
9060+
if not md5 then
9061+
return false, "md5 new error"
9062+
end
9063+
9064+
local ok = md5:update(str)
9065+
if not ok then
9066+
return false, "md5 update error"
9067+
end
9068+
9069+
local digest = md5:final()
9070+
return true, resty_str.to_hex(digest)
9071+
end
9072+
return {md5=md5}
9073+
```
9074+
9075+
Example2: write logs into the log file.
9076+
9077+
```nginx
9078+
9079+
location /write_log_file {
9080+
default_type 'text/plain';
9081+
9082+
content_by_lua_block {
9083+
local ok, err = ngx.run_worker_thread("testpool", "write_log_file", "log", ngx.var.arg_str)
9084+
if not ok then
9085+
ngx.say(ok, " : ", err)
9086+
return
9087+
end
9088+
ngx.say(ok)
9089+
}
9090+
}
9091+
```
9092+
9093+
`write_log_file.lua`
9094+
9095+
```lua
9096+
9097+
local function log(str)
9098+
local file, err = io.open("/tmp/tmp.log", "a")
9099+
if not file then
9100+
return false, err
9101+
end
9102+
file:write(str)
9103+
file:flush()
9104+
file:close()
9105+
return true
9106+
end
9107+
return {log=log}
9108+
```
9109+
9110+
[Back to TOC](#nginx-api-for-lua)
9111+
89639112
Obsolete Sections
89649113
=================
89659114

config

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,7 @@ HTTP_LUA_SRCS=" \
296296
$ngx_addon_dir/src/ngx_http_lua_log_ringbuf.c \
297297
$ngx_addon_dir/src/ngx_http_lua_input_filters.c \
298298
$ngx_addon_dir/src/ngx_http_lua_pipe.c \
299+
$ngx_addon_dir/src/ngx_http_lua_worker_thread.c \
299300
"
300301

301302
HTTP_LUA_DEPS=" \
@@ -355,6 +356,7 @@ HTTP_LUA_DEPS=" \
355356
$ngx_addon_dir/src/ngx_http_lua_log_ringbuf.h \
356357
$ngx_addon_dir/src/ngx_http_lua_input_filters.h \
357358
$ngx_addon_dir/src/ngx_http_lua_pipe.h \
359+
$ngx_addon_dir/src/ngx_http_lua_worker_thread.h \
358360
"
359361

360362
# ----------------------------------------

doc/HttpLuaModule.wiki

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2824,6 +2824,22 @@ This allows Lua I/O primitives to not be interrupted by Nginx's handling of vari
28242824
28252825
This directive was first introduced in the <code>v0.10.14</code> release.
28262826
2827+
== lua_worker_thread_vm_pool_size ==
2828+
2829+
'''syntax:''' ''lua_worker_thread_vm_pool_size <size>''
2830+
2831+
'''default:''' ''lua_worker_thread_vm_pool_size 100''
2832+
2833+
'''context:''' ''http''
2834+
2835+
Specifies the size limit of the Lua VM pool (default 100) that will be used in the [ngx.run_worker_thread](#ngxrun_worker_thread) API.
2836+
2837+
Also, it is not allowed to create Lua VMs that exceeds the pool size limit.
2838+
2839+
The Lua VM in the VM pool is used to execute Lua code in seperate thread.
2840+
2841+
The pool is global at Nginx worker level. And it is used to reuse Lua VMs between requests.
2842+
28272843
= Nginx API for Lua =
28282844
28292845
<!-- inline-toc -->
@@ -7671,6 +7687,126 @@ This API was first usable in the context of [[#init_by_lua|init_by_lua*]] since
76717687
76727688
This API was first enabled in the <code>v0.6.0</code> release.
76737689
7690+
== ngx.run_worker_thread ==
7691+
7692+
'''syntax:''' ''ok, res1, res2, ... = ngx.run_worker_thread(threadpool, module_name, func_name, arg1, arg2, ...)''
7693+
7694+
'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*''
7695+
7696+
'''This API is still experimental and may change in the future without notice.'''
7697+
7698+
'''This API is available only for Linux.'''
7699+
7700+
Wrap the [http://nginx.org/en/docs/dev/development_guide.html#threads nginx worker thread] to execute lua function. The caller coroutine would yield until the function returns.
7701+
7702+
Note that no ngx_lua API can be used in the `function_name` function of the `module` module since it is invoked in a separate thread.
7703+
7704+
The first argument `threadpool` specifies the Nginx thread pool name defined by [thread_pool](https://nginx.org/en/docs/ngx_core_module.html#thread_pool).
7705+
7706+
The second argument <code>module_name</code> specifies the lua module name to execute in the worker thread, which would return a lua table. The module must be inside the package path, e.g.
7707+
7708+
<geshi lang="nginx">
7709+
lua_package_path '/opt/openresty/?.lua;;';
7710+
</geshi>
7711+
7712+
The third argument <code>func_name</code> specifies the function field in the module table as the second argument.
7713+
7714+
The type of <code>arg</code>s must be one of type below:
7715+
7716+
* boolean
7717+
* number
7718+
* string
7719+
* nil
7720+
* table (the table may be recursive, and contains members of types above.)
7721+
7722+
The <code>ok</code> is in boolean type, which indicate the C land error (failed to get thread from thread pool, pcall the module function failed, .etc). If <code>ok</code> is <code>false</code>, the <code>res1</code> is the error string.
7723+
7724+
The return values (res1, ...) are returned by invocation of the module function. Normally, the <code>res1</code> should be in boolean type, so that the caller could inspect the error.
7725+
7726+
This API is useful when you need to execute the below types of tasks:
7727+
7728+
* CPU bound task, e.g. do md5 calculation
7729+
* File I/O task
7730+
* Call <code>os.execute()</code> or blocking C API via <code>ffi</code>
7731+
* Call external Lua library not based on cosocket or nginx
7732+
7733+
Example1: do md5 calculation.
7734+
7735+
<geshi lang="nginx">
7736+
location /calc_md5 {
7737+
default_type 'text/plain';
7738+
7739+
content_by_lua_block {
7740+
local ok, ret, md5_or_err = ngx.run_worker_thread("testpool", "calc_md5", "md5", ngx.var.arg_str)
7741+
if not ok then
7742+
ngx.say(ret)
7743+
return
7744+
end
7745+
if not ret then
7746+
ngx.say(md5_or_err)
7747+
return
7748+
end
7749+
ngx.say(md5_or_err)
7750+
}
7751+
}
7752+
</geshi>
7753+
7754+
<code>calc_md5.lua</code>
7755+
7756+
<geshi lang="lua">
7757+
local resty_md5 = require "resty.md5"
7758+
local resty_str = require "resty.string"
7759+
7760+
local function md5(str)
7761+
local md5 = resty_md5:new()
7762+
if not md5 then
7763+
return false, "md5 new error"
7764+
end
7765+
7766+
local ok = md5:update(str)
7767+
if not ok then
7768+
return false, "md5 update error"
7769+
end
7770+
7771+
local digest = md5:final()
7772+
return true, resty_str.to_hex(digest)
7773+
end
7774+
return {md5=md5}
7775+
</geshi>
7776+
7777+
Example2: write logs into the log file.
7778+
7779+
<geshi lang="nginx">
7780+
location /write_log_file {
7781+
default_type 'text/plain';
7782+
7783+
content_by_lua_block {
7784+
local ok, err = ngx.run_worker_thread("testpool", "write_log_file", "log", ngx.var.arg_str)
7785+
if not ok then
7786+
ngx.say(ok, " : ", err)
7787+
return
7788+
end
7789+
ngx.say(ok)
7790+
}
7791+
}
7792+
</geshi>
7793+
7794+
<code>write_log_file.lua</code>
7795+
7796+
<geshi lang="lua">
7797+
local function log(str)
7798+
local file, err = io.open("/tmp/tmp.log", "a")
7799+
if not file then
7800+
return false, err
7801+
end
7802+
file:write(str)
7803+
file:flush()
7804+
file:close()
7805+
return true
7806+
end
7807+
return {log=log}
7808+
</geshi>
7809+
76747810
= Obsolete Sections =
76757811
76767812
This section is just holding obsolete documentation sections that have been either renamed or removed so that existing links over the web are still valid.

src/ngx_http_lua_common.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,8 @@ struct ngx_http_lua_main_conf_s {
288288
ngx_queue_t free_lua_threads; /* of ngx_http_lua_thread_ref_t */
289289
ngx_queue_t cached_lua_threads; /* of ngx_http_lua_thread_ref_t */
290290

291+
ngx_uint_t worker_thread_vm_pool_size;
292+
291293
unsigned requires_header_filter:1;
292294
unsigned requires_body_filter:1;
293295
unsigned requires_capture_filter:1;

src/ngx_http_lua_module.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -646,6 +646,13 @@ static ngx_command_t ngx_http_lua_cmds[] = {
646646
0,
647647
NULL },
648648

649+
{ ngx_string("lua_worker_thread_vm_pool_size"),
650+
NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1,
651+
ngx_conf_set_num_slot,
652+
NGX_HTTP_MAIN_CONF_OFFSET,
653+
offsetof(ngx_http_lua_main_conf_t, worker_thread_vm_pool_size),
654+
NULL },
655+
649656
ngx_null_command
650657
};
651658

@@ -975,6 +982,8 @@ ngx_http_lua_create_main_conf(ngx_conf_t *cf)
975982
return NULL;
976983
}
977984

985+
lmcf->worker_thread_vm_pool_size = NGX_CONF_UNSET;
986+
978987
dd("nginx Lua module main config structure initialized!");
979988

980989
return lmcf;
@@ -1058,6 +1067,10 @@ ngx_http_lua_init_main_conf(ngx_conf_t *cf, void *conf)
10581067
}
10591068
#endif
10601069

1070+
if (lmcf->worker_thread_vm_pool_size == NGX_CONF_UNSET_UINT) {
1071+
lmcf->worker_thread_vm_pool_size = 100;
1072+
}
1073+
10611074
return NGX_CONF_OK;
10621075
}
10631076

0 commit comments

Comments
 (0)