Skip to content

Commit 189ba24

Browse files
spacewanderthibaultcha
authored andcommitted
feature: when a timer fails to run we now log the location of its function's definition.
Signed-off-by: Thibault Charbonnier <thibaultcha@me.com>
1 parent 4b9e53f commit 189ba24

File tree

2 files changed

+169
-25
lines changed

2 files changed

+169
-25
lines changed

src/ngx_http_lua_timer.c

Lines changed: 38 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@
1616
#include "ngx_http_lua_probe.h"
1717

1818

19+
#define NGX_HTTP_LUA_TIMER_ERRBUF_SIZE 128
20+
21+
1922
typedef struct {
2023
void **main_conf;
2124
void **srv_conf;
@@ -559,12 +562,20 @@ ngx_http_lua_timer_handler(ngx_event_t *ev)
559562
ngx_http_lua_main_conf_t *lmcf;
560563
ngx_http_core_loc_conf_t *clcf;
561564

565+
lua_Debug ar;
566+
u_char *p;
567+
u_char errbuf[NGX_HTTP_LUA_TIMER_ERRBUF_SIZE];
568+
const char *source;
569+
const char *errmsg;
570+
562571
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
563572
"lua ngx.timer expired");
564573

565574
ngx_memcpy(&tctx, ev->data, sizeof(ngx_http_lua_timer_ctx_t));
566575
ngx_free(ev);
567576

577+
ngx_http_lua_assert(tctx.co_ref && tctx.co);
578+
568579
lmcf = tctx.lmcf;
569580

570581
lmcf->pending_timers--;
@@ -579,17 +590,17 @@ ngx_http_lua_timer_handler(ngx_event_t *ev)
579590
}
580591

581592
if (lmcf->running_timers >= lmcf->max_running_timers) {
582-
ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0,
583-
"%i lua_max_running_timers are not enough",
584-
lmcf->max_running_timers);
593+
p = ngx_snprintf(errbuf, NGX_HTTP_LUA_TIMER_ERRBUF_SIZE - 1,
594+
"%i lua_max_running_timers are not enough",
595+
lmcf->max_running_timers);
596+
*p = '\0';
597+
errmsg = (const char *) errbuf;
585598
goto failed;
586599
}
587600

588601
c = ngx_http_lua_create_fake_connection(tctx.pool);
589602
if (c == NULL) {
590-
ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0,
591-
"failed to create fake connection to run timer (co: %p)",
592-
tctx.co);
603+
errmsg = "could not create fake connection";
593604
goto failed;
594605
}
595606

@@ -601,9 +612,7 @@ ngx_http_lua_timer_handler(ngx_event_t *ev)
601612

602613
r = ngx_http_lua_create_fake_request(c);
603614
if (r == NULL) {
604-
ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0,
605-
"failed to create fake request to run timer (co: %p)",
606-
tctx.co);
615+
errmsg = "could not create fake request";
607616
goto failed;
608617
}
609618

@@ -624,8 +633,7 @@ ngx_http_lua_timer_handler(ngx_event_t *ev)
624633

625634
ctx = ngx_http_lua_create_ctx(r);
626635
if (ctx == NULL) {
627-
ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0,
628-
"failed to create ctx to run timer (co: %p)", tctx.co);
636+
errmsg = "could not create ctx";
629637
goto failed;
630638
}
631639

@@ -634,9 +642,7 @@ ngx_http_lua_timer_handler(ngx_event_t *ev)
634642

635643
pcln = ngx_pool_cleanup_add(r->pool, 0);
636644
if (pcln == NULL) {
637-
ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0,
638-
"failed to add vm cleanup to run timer (co: %p)",
639-
tctx.co);
645+
errmsg = "could not add vm cleanup";
640646
goto failed;
641647
}
642648

@@ -650,9 +656,7 @@ ngx_http_lua_timer_handler(ngx_event_t *ev)
650656

651657
cln = ngx_http_cleanup_add(r, 0);
652658
if (cln == NULL) {
653-
ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0,
654-
"failed to add request cleanup to run timer (co: %p)",
655-
tctx.co);
659+
errmsg = "could not add request cleanup";
656660
goto failed;
657661
}
658662

@@ -709,14 +713,25 @@ ngx_http_lua_timer_handler(ngx_event_t *ev)
709713

710714
failed:
711715

712-
if (tctx.co_ref && tctx.co) {
713-
lua_pushlightuserdata(tctx.co, ngx_http_lua_lightudata_mask(
714-
coroutines_key));
715-
lua_rawget(tctx.co, LUA_REGISTRYINDEX);
716-
luaL_unref(tctx.co, -1, tctx.co_ref);
717-
lua_settop(tctx.co, 0);
716+
/* co stack: func [args] */
717+
lua_getinfo(tctx.co, ">Sf", &ar);
718+
719+
source = ar.source;
720+
721+
if (source == NULL) {
722+
source = "(unknown)";
718723
}
719724

725+
ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0,
726+
"lua failed to run timer with function defined at %s:%d: %s",
727+
source, ar.linedefined, errmsg);
728+
729+
lua_pushlightuserdata(tctx.co, ngx_http_lua_lightudata_mask(
730+
coroutines_key));
731+
lua_rawget(tctx.co, LUA_REGISTRYINDEX);
732+
luaL_unref(tctx.co, -1, tctx.co_ref);
733+
lua_settop(tctx.co, 0);
734+
720735
if (tctx.vm_state) {
721736
ngx_http_lua_cleanup_vm(tctx.vm_state);
722737
}

t/106-timer.t

Lines changed: 131 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ our $StapScript = $t::StapThread::StapScript;
1212

1313
repeat_each(2);
1414

15-
plan tests => repeat_each() * (blocks() * 8 + 72);
15+
plan tests => repeat_each() * (blocks() * 8 + 63);
1616

1717
#no_diff();
1818
no_long_string();
@@ -1932,7 +1932,7 @@ registered timer
19321932

19331933
--- error_log eval
19341934
[
1935-
qr/\[alert\] .*? 1 lua_max_running_timers are not enough/,
1935+
qr/\[alert\] .*? lua failed to run timer with function defined at =content_by_lua\(nginx.conf:\d+\):10: 1 lua_max_running_timers are not enough/,
19361936
"lua ngx.timer expired",
19371937
"http lua close fake http connection",
19381938
]
@@ -2193,3 +2193,132 @@ ok
21932193
--- error_log
21942194
Bad bad bad
21952195
--- skip_nginx: 4: < 1.7.1
2196+
2197+
2198+
2199+
=== TEST 33: log function location when failed to run a timer
2200+
--- http_config
2201+
lua_max_running_timers 1;
2202+
--- config
2203+
location /t {
2204+
content_by_lua_block {
2205+
local function g()
2206+
ngx.sleep(0.01)
2207+
end
2208+
2209+
local function f()
2210+
ngx.sleep(0.01)
2211+
end
2212+
2213+
local ok, err = ngx.timer.at(0, f)
2214+
if not ok then
2215+
ngx.say("failed to create timer f: ", err)
2216+
return
2217+
end
2218+
2219+
local ok, err = ngx.timer.at(0, g)
2220+
if not ok then
2221+
ngx.say("failed to create timer g: ", err)
2222+
return
2223+
end
2224+
2225+
ngx.say("ok")
2226+
}
2227+
}
2228+
--- request
2229+
GET /t
2230+
--- response_body
2231+
ok
2232+
--- wait: 0.1
2233+
--- error_log eval
2234+
qr/\[alert\] .*? lua failed to run timer with function defined at =content_by_lua\(nginx.conf:\d+\):2: 1 lua_max_running_timers are not enough/
2235+
--- no_error_log
2236+
[crit]
2237+
[error]
2238+
2239+
2240+
2241+
=== TEST 34: log function location when failed to run a timer (anonymous function)
2242+
--- http_config
2243+
lua_max_running_timers 1;
2244+
--- config
2245+
location /t {
2246+
content_by_lua_block {
2247+
local function f()
2248+
ngx.sleep(0.01)
2249+
end
2250+
2251+
local ok, err = ngx.timer.at(0, f)
2252+
if not ok then
2253+
ngx.say("failed to set timer f: ", err)
2254+
return
2255+
end
2256+
2257+
local ok, err = ngx.timer.at(0, function()
2258+
ngx.sleep(0.01)
2259+
end)
2260+
2261+
if not ok then
2262+
ngx.say("failed to set timer: ", err)
2263+
return
2264+
end
2265+
2266+
ngx.say("ok")
2267+
}
2268+
}
2269+
--- request
2270+
GET /t
2271+
--- response_body
2272+
ok
2273+
--- wait: 0.1
2274+
--- error_log eval
2275+
qr/\[alert\] .*? lua failed to run timer with function defined at =content_by_lua\(nginx.conf:\d+\):12: 1 lua_max_running_timers are not enough/
2276+
--- no_error_log
2277+
[crit]
2278+
[error]
2279+
2280+
2281+
2282+
=== TEST 35: log function location when failed to run a timer (lua file)
2283+
--- user_files
2284+
>>> test.lua
2285+
local _M = {}
2286+
2287+
function _M.run()
2288+
ngx.sleep(0.01)
2289+
end
2290+
2291+
return _M
2292+
--- http_config
2293+
lua_package_path '$TEST_NGINX_HTML_DIR/?.lua;./?.lua;;';
2294+
lua_max_running_timers 1;
2295+
--- config
2296+
location /t {
2297+
content_by_lua_block {
2298+
local test = require "test"
2299+
2300+
local ok, err = ngx.timer.at(0, test.run)
2301+
if not ok then
2302+
ngx.say("failed to set timer: ", err)
2303+
return
2304+
end
2305+
2306+
local ok, err = ngx.timer.at(0, test.run)
2307+
if not ok then
2308+
ngx.say("failed to set timer: ", err)
2309+
return
2310+
end
2311+
2312+
ngx.say("ok")
2313+
}
2314+
}
2315+
--- request
2316+
GET /t
2317+
--- response_body
2318+
ok
2319+
--- wait: 0.1
2320+
--- no_error_log
2321+
[crit]
2322+
[error]
2323+
--- error_log eval
2324+
qr/\[alert\] .*? lua failed to run timer with function defined at @.+\/test.lua:3: 1 lua_max_running_timers are not enough/

0 commit comments

Comments
 (0)