Skip to content

Commit 9a5b4c2

Browse files
authored
fix: remove request level pipe proc in openresty 1.21.4.2 (#78)
openresty optimized the pipe api and destroyed the pipeline process at the end of the request. The APISIX plugin runner process lifecycle does not apply to request level, Instead, it is pulled up in advance and processed continuously through RPC calls until the process exits. Patches: * lua-resty-core-pipe_runner.patch * ngx_lua-pipe_runner.patch
1 parent 1b21340 commit 9a5b4c2

File tree

3 files changed

+310
-0
lines changed

3 files changed

+310
-0
lines changed
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
diff --git lib/ngx/pipe.lua lib/ngx/pipe.lua
2+
index 3757ab7..413a10e 100644
3+
--- lib/ngx/pipe.lua
4+
+++ lib/ngx/pipe.lua
5+
@@ -47,8 +47,7 @@ typedef struct {
6+
ngx_http_lua_pipe_t *pipe;
7+
} ngx_http_lua_ffi_pipe_proc_t;
8+
9+
-int ngx_http_lua_ffi_pipe_spawn(ngx_http_request_t *r,
10+
- ngx_http_lua_ffi_pipe_proc_t *proc,
11+
+int ngx_http_lua_ffi_pipe_spawn(ngx_http_lua_ffi_pipe_proc_t *proc,
12+
const char *file, const char **argv, int merge_stderr, size_t buffer_size,
13+
const char **environ, u_char *errbuf, size_t *errbuf_size);
14+
15+
@@ -625,9 +624,8 @@ do
16+
17+
local errbuf = get_string_buf(ERR_BUF_SIZE)
18+
local errbuf_size = get_size_ptr()
19+
- local r = get_request()
20+
errbuf_size[0] = ERR_BUF_SIZE
21+
- local rc = C.ngx_http_lua_ffi_pipe_spawn(r, proc, exe, proc_args,
22+
+ local rc = C.ngx_http_lua_ffi_pipe_spawn(proc, exe, proc_args,
23+
merge_stderr, buffer_size,
24+
proc_envs, errbuf, errbuf_size)
25+
if rc == FFI_ERROR then
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
diff --git src/ngx_http_lua_pipe.c src/ngx_http_lua_pipe.c
2+
index 8c0884bc..8369160f 100644
3+
--- src/ngx_http_lua_pipe.c
4+
+++ src/ngx_http_lua_pipe.c
5+
@@ -599,8 +599,7 @@ ngx_http_lua_execvpe(const char *program, char * const argv[],
6+
7+
8+
int
9+
-ngx_http_lua_ffi_pipe_spawn(ngx_http_request_t *r,
10+
- ngx_http_lua_ffi_pipe_proc_t *proc,
11+
+ngx_http_lua_ffi_pipe_spawn(ngx_http_lua_ffi_pipe_proc_t *proc,
12+
const char *file, const char **argv, int merge_stderr, size_t buffer_size,
13+
const char **environ, u_char *errbuf, size_t *errbuf_size)
14+
{
15+
@@ -620,7 +619,6 @@ ngx_http_lua_ffi_pipe_spawn(ngx_http_request_t *r,
16+
ngx_http_lua_pipe_node_t *pipe_node;
17+
struct sigaction sa;
18+
ngx_http_lua_pipe_signal_t *sig;
19+
- ngx_pool_cleanup_t *cln;
20+
sigset_t set;
21+
22+
pool_size = ngx_align(NGX_MIN_POOL_SIZE + buffer_size * 2,
23+
@@ -908,21 +906,6 @@ ngx_http_lua_ffi_pipe_spawn(ngx_http_request_t *r,
24+
pp->stderr_fd = stderr_fd;
25+
}
26+
27+
- if (pp->cleanup == NULL) {
28+
- cln = ngx_pool_cleanup_add(r->pool, 0);
29+
-
30+
- if (cln == NULL) {
31+
- *errbuf_size = ngx_snprintf(errbuf, *errbuf_size, "no memory")
32+
- - errbuf;
33+
- goto close_in_out_err_fd;
34+
- }
35+
-
36+
- cln->handler = (ngx_pool_cleanup_pt) ngx_http_lua_ffi_pipe_proc_destroy;
37+
- cln->data = proc;
38+
- pp->cleanup = &cln->handler;
39+
- pp->r = r;
40+
- }
41+
-
42+
node = (ngx_rbtree_node_t *) (pp + 1);
43+
node->key = pid;
44+
pipe_node = (ngx_http_lua_pipe_node_t *) &node->color;
45+
@@ -1193,12 +1176,6 @@ ngx_http_lua_ffi_pipe_proc_destroy(ngx_http_lua_ffi_pipe_proc_t *proc)
46+
}
47+
}
48+
49+
- if (pipe->cleanup != NULL) {
50+
- *pipe->cleanup = NULL;
51+
- ngx_http_lua_cleanup_free(pipe->r, pipe->cleanup);
52+
- pipe->cleanup = NULL;
53+
- }
54+
-
55+
ngx_http_lua_pipe_proc_finalize(proc);
56+
ngx_destroy_pool(pipe->pool);
57+
proc->pipe = NULL;
58+
diff --git src/ngx_http_lua_pipe.h src/ngx_http_lua_pipe.h
59+
index f1c92835..ecb86c88 100644
60+
--- src/ngx_http_lua_pipe.h
61+
+++ src/ngx_http_lua_pipe.h
62+
@@ -57,8 +57,6 @@ struct ngx_http_lua_pipe_s {
63+
ngx_http_lua_pipe_ctx_t *stdout_ctx;
64+
ngx_http_lua_pipe_ctx_t *stderr_ctx;
65+
ngx_http_lua_pipe_retval_handler retval_handler;
66+
- ngx_http_cleanup_pt *cleanup;
67+
- ngx_http_request_t *r;
68+
size_t buffer_size;
69+
unsigned closed:1;
70+
unsigned dead:1;

t/pipe.t

Lines changed: 215 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,215 @@
1+
use t::APISIX_NGINX 'no_plan';
2+
3+
4+
add_block_preprocessor(sub {
5+
my ($block) = @_;
6+
7+
if (!$block->request) {
8+
$block->set_value("request", "GET /t");
9+
}
10+
});
11+
12+
run_tests;
13+
14+
__DATA__
15+
16+
=== TEST 1: check pipe spawn arguments
17+
--- config
18+
location = /t {
19+
content_by_lua_block {
20+
local ngx_pipe = require "ngx.pipe"
21+
22+
local function check_error(...)
23+
local data, err = pcall(...)
24+
if not data then
25+
ngx.say(err)
26+
else
27+
ngx.say('ok')
28+
end
29+
end
30+
31+
check_error(ngx_pipe.spawn, nil)
32+
check_error(ngx_pipe.spawn, {})
33+
check_error(ngx_pipe.spawn, {"ls"}, {buffer_size = 0})
34+
check_error(ngx_pipe.spawn, {"ls"}, {buffer_size = 0.5})
35+
check_error(ngx_pipe.spawn, {"ls"}, {buffer_size = "1"})
36+
check_error(ngx_pipe.spawn, {"ls"}, {buffer_size = true})
37+
}
38+
}
39+
--- request
40+
--- response_body
41+
bad args arg: table expected, got nil
42+
bad args arg: non-empty table expected
43+
bad buffer_size option
44+
bad buffer_size option
45+
ok
46+
bad buffer_size option
47+
48+
49+
50+
=== TEST 2: spawn process, with buffer_size option
51+
--- config
52+
location = /t {
53+
content_by_lua_block {
54+
local ngx_pipe = require "ngx.pipe"
55+
local proc, err = ngx_pipe.spawn({"ls"}, {buffer_size = 256})
56+
if not proc then
57+
ngx.say(err)
58+
else
59+
ngx.say('ok')
60+
end
61+
}
62+
}
63+
--- response_body
64+
ok
65+
--- error_log eval
66+
qr/lua pipe spawn process:[0-9A-F]+ pid:\d+ merge_stderr:0 buffer_size:256/
67+
--- no_error_log
68+
[error]
69+
70+
71+
72+
=== TEST 3: ensure process is destroyed in GC
73+
--- config
74+
location = /t {
75+
content_by_lua_block {
76+
local ngx_pipe = require "ngx.pipe"
77+
do
78+
local proc, err = ngx_pipe.spawn({"ls", "-l"})
79+
if not proc then
80+
ngx.say(err)
81+
return
82+
end
83+
end
84+
85+
collectgarbage()
86+
ngx.say("ok")
87+
}
88+
}
89+
--- response_body
90+
ok
91+
--- no_error_log
92+
[error]
93+
--- error_log
94+
lua pipe destroy process:
95+
96+
97+
98+
=== TEST 4: check phase for process wait
99+
--- config
100+
location = /t {
101+
content_by_lua_block {
102+
local ngx_pipe = require "ngx.pipe"
103+
local proc, err = ngx_pipe.spawn({"sleep", 0.1})
104+
if not proc then
105+
ngx.say(err)
106+
return
107+
end
108+
109+
package.loaded.proc = proc
110+
}
111+
112+
log_by_lua_block {
113+
package.loaded.proc:wait()
114+
}
115+
}
116+
--- error_log
117+
API disabled in the context of log_by_lua
118+
119+
120+
121+
=== TEST 5: check process wait arguments
122+
--- config
123+
location = /t {
124+
content_by_lua_block {
125+
local ngx_pipe = require "ngx.pipe"
126+
local proc, err = ngx_pipe.spawn({"sleep", 0.1})
127+
proc.wait()
128+
}
129+
}
130+
--- error_code: 500
131+
--- ignore_response_body
132+
--- error_log eval
133+
qr/\[error\] .*? runtime error: content_by_lua\(nginx\.conf\:\d+\):\d+: not a process instance/
134+
--- no_error_log
135+
[crit]
136+
137+
138+
139+
=== TEST 6: wait an already waited process
140+
--- config
141+
location = /t {
142+
content_by_lua_block {
143+
local ngx_pipe = require "ngx.pipe"
144+
local proc, err = ngx_pipe.spawn({"ls"})
145+
if not proc then
146+
ngx.say(err)
147+
return
148+
end
149+
150+
local ok, err = proc:wait()
151+
if not ok then
152+
ngx.say(err)
153+
return
154+
end
155+
156+
local ok, err = proc:wait()
157+
if not ok then
158+
ngx.say(err)
159+
end
160+
}
161+
}
162+
--- response_body
163+
exited
164+
165+
166+
167+
=== TEST 7: more than one coroutines wait a process
168+
--- config
169+
location = /t {
170+
content_by_lua_block {
171+
local ngx_pipe = require "ngx.pipe"
172+
local proc, err = ngx_pipe.spawn({"sleep", 0.1})
173+
if not proc then
174+
ngx.say(err)
175+
return
176+
end
177+
178+
local function wait()
179+
local ok, err = proc:wait()
180+
if not ok then
181+
ngx.say(err)
182+
end
183+
end
184+
185+
local th1 = ngx.thread.spawn(wait)
186+
local th2 = ngx.thread.spawn(wait)
187+
ngx.thread.wait(th1)
188+
ngx.thread.wait(th2)
189+
ngx.thread.spawn(wait)
190+
}
191+
}
192+
--- response_body
193+
pipe busy waiting
194+
exited
195+
196+
197+
198+
=== TEST 8: kill living sub-process during Lua VM destruction.
199+
--- config
200+
location = /t {
201+
content_by_lua_block {
202+
local ngx_pipe = require "ngx.pipe"
203+
local proc, err = ngx_pipe.spawn({"sleep", 3600})
204+
if not proc then
205+
ngx.say(err)
206+
return
207+
end
208+
ngx.say("ok")
209+
}
210+
}
211+
--- response_body
212+
ok
213+
--- shutdown_error_log
214+
lua pipe destroy process:
215+
lua pipe kill process:

0 commit comments

Comments
 (0)