Skip to content

Commit 14ae8f5

Browse files
committed
feature: allow ngx.sleep to be used blockingly in non-yieldable phases
Allow ngx.sleep everywhere simplify the application's logic. Now we don't need to write a fallback if the same function need to be run in non-yieldable phases. Close openresty#1730.
1 parent fd25474 commit 14ae8f5

6 files changed

+99
-23
lines changed

README.markdown

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5621,14 +5621,17 @@ ngx.sleep
56215621

56225622
**syntax:** *ngx.sleep(seconds)*
56235623

5624-
**context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua**
5624+
**context:** *init_by_lua*, 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*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*, exit_worker_by_lua**
56255625

5626-
Sleeps for the specified seconds without blocking. One can specify time resolution up to 0.001 seconds (i.e., one millisecond).
5626+
Sleeps for the specified seconds without blocking in yieldable phases or blockingly in other phases.
5627+
One can specify time resolution up to 0.001 seconds (i.e., one millisecond).
56275628

56285629
Behind the scene, this method makes use of the Nginx timers.
56295630

56305631
Since the `0.7.20` release, The `0` time argument can also be specified.
56315632

5633+
Since the `FIXME` release, this method can be used in non-yieldable phases blockingly.
5634+
56325635
This method was introduced in the `0.5.0rc30` release.
56335636

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

doc/HttpLuaModule.wiki

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4720,14 +4720,17 @@ Since <code>v0.8.3</code> this function returns <code>1</code> on success, or re
47204720
47214721
'''syntax:''' ''ngx.sleep(seconds)''
47224722
4723-
'''context:''' ''rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, ssl_certificate_by_lua*, ssl_session_fetch_by_lua*''
4723+
'''context:''' ''init_by_lua*, 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*, ssl_session_fetch_by_lua*, ssl_session_store_by_lua*, exit_worker_by_lua*''
47244724
4725-
Sleeps for the specified seconds without blocking. One can specify time resolution up to 0.001 seconds (i.e., one millisecond).
4725+
Sleeps for the specified seconds without blocking in yieldable phases or blockingly in other phases.
4726+
One can specify time resolution up to 0.001 seconds (i.e., one millisecond).
47264727
47274728
Behind the scene, this method makes use of the Nginx timers.
47284729
47294730
Since the <code>0.7.20</code> release, The <code>0</code> time argument can also be specified.
47304731
4732+
Since the <code>FIXME</code> release, this method can be used in non-yieldable phases blockingly.
4733+
47314734
This method was introduced in the <code>0.5.0rc30</code> release.
47324735
47334736
== ngx.escape_uri ==

src/ngx_http_lua_sleep.c

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,23 +36,34 @@ ngx_http_lua_ngx_sleep(lua_State *L)
3636
return luaL_error(L, "attempt to pass %d arguments, but accepted 1", n);
3737
}
3838

39-
r = ngx_http_lua_get_req(L);
40-
if (r == NULL) {
41-
return luaL_error(L, "no request found");
42-
}
43-
4439
delay = (ngx_int_t) (luaL_checknumber(L, 1) * 1000);
4540

4641
if (delay < 0) {
4742
return luaL_error(L, "invalid sleep duration \"%d\"", delay);
4843
}
4944

45+
r = ngx_http_lua_get_req(L);
46+
if (r == NULL) {
47+
/* init_by_lua phase */
48+
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
49+
"lua ready to sleep for %d ms", delay);
50+
51+
ngx_msleep(delay);
52+
return 0;
53+
}
54+
5055
ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
5156
if (ctx == NULL) {
5257
return luaL_error(L, "no request ctx found");
5358
}
5459

55-
ngx_http_lua_check_context(L, ctx, NGX_HTTP_LUA_CONTEXT_YIELDABLE);
60+
if (!(ctx->context & NGX_HTTP_LUA_CONTEXT_YIELDABLE)) {
61+
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
62+
"lua ready to sleep for %d ms", delay);
63+
64+
ngx_msleep(delay);
65+
return 0;
66+
}
5667

5768
coctx = ctx->cur_co_ctx;
5869
if (coctx == NULL) {

t/077-sleep.t

Lines changed: 69 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ log_level('debug');
99

1010
repeat_each(2);
1111

12-
plan tests => repeat_each() * 71;
12+
plan tests => repeat_each() * (blocks() * 4);
1313

1414
#no_diff();
1515
no_long_string();
@@ -237,21 +237,20 @@ lua sleep timer expired: "/test?"
237237

238238

239239

240-
=== TEST 10: ngx.sleep unavailable in log_by_lua
240+
=== TEST 10: ngx.sleep available in log_by_lua
241241
--- config
242242
location /t {
243243
echo hello;
244-
log_by_lua '
245-
ngx.sleep(0.1)
246-
';
244+
log_by_lua_block {
245+
ngx.sleep(0.001)
246+
}
247247
}
248248
--- request
249249
GET /t
250250
--- response_body
251251
hello
252-
--- wait: 0.1
253252
--- error_log
254-
API disabled in the context of log_by_lua*
253+
lua ready to sleep for 1 ms
255254

256255

257256

@@ -500,3 +499,66 @@ f end
500499
worker cycle
501500
e?poll timer: 0
502501
/
502+
503+
504+
505+
=== TEST 18: ngx.sleep(0) in no-yieldable phases
506+
--- config
507+
location /t {
508+
echo hello;
509+
log_by_lua_block {
510+
ngx.sleep(0)
511+
}
512+
}
513+
--- request
514+
GET /t
515+
--- response_body
516+
hello
517+
--- error_log
518+
lua ready to sleep for 0 ms
519+
520+
521+
522+
=== TEST 19: ngx.sleep available in init_worker_by_lua
523+
--- http_config
524+
init_worker_by_lua_block {
525+
local start = ngx.now()
526+
ngx.sleep(0.1)
527+
ngx.update_time()
528+
package.loaded.gap = ngx.now() - start
529+
}
530+
--- config
531+
location /t {
532+
content_by_lua_block {
533+
ngx.say(package.loaded.gap >= 0.1)
534+
}
535+
}
536+
--- request
537+
GET /t
538+
--- no_error_log
539+
[error]
540+
--- response_body
541+
true
542+
543+
544+
545+
=== TEST 20: ngx.sleep available in init_by_lua
546+
--- http_config
547+
init_by_lua_block {
548+
local start = ngx.now()
549+
ngx.sleep(0.1)
550+
ngx.update_time()
551+
package.loaded.gap = ngx.now() - start
552+
}
553+
--- config
554+
location /t {
555+
content_by_lua_block {
556+
ngx.say(package.loaded.gap >= 0.1)
557+
}
558+
}
559+
--- request
560+
GET /t
561+
--- no_error_log
562+
[error]
563+
--- response_body
564+
true

t/138-balancer.t

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -272,10 +272,8 @@ qr/\[error\] .*? failed to run balancer_by_lua\*: balancer_by_lua:2: API disable
272272
}
273273
--- request
274274
GET /t
275-
--- response_body_like: 500 Internal Server Error
276-
--- error_code: 500
277-
--- error_log eval
278-
qr/\[error\] .*? failed to run balancer_by_lua\*: balancer_by_lua:2: API disabled in the context of balancer_by_lua\*/
275+
--- response_body_like: 502 Bad Gateway
276+
--- error_code: 502
279277
280278
281279

t/142-ssl-session-store.t

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ ssl_session_store_by_lua_block:1: ssl session store by lua is running!,
9595
9696
9797
98-
=== TEST 2: sleep is not allowed
98+
=== TEST 2: sleep is allowed
9999
--- http_config
100100
ssl_session_store_by_lua_block {
101101
local begin = ngx.now()
@@ -157,7 +157,6 @@ close: 1 nil
157157
158158
--- error_log
159159
lua ssl server name: "test.com"
160-
API disabled in the context of ssl_session_store_by_lua*
161160
162161
--- no_error_log
163162
[alert]

0 commit comments

Comments
 (0)