@@ -16,13 +16,60 @@ local timer_id = 0
1616local now = ngx .now
1717local sleep = ngx .sleep
1818local exiting = ngx .worker .exiting
19+ local min = math.min
1920
2021local KEY_PREFIX = " [lua-resty-timer]"
2122local LOG_PREFIX = " [resty-timer] "
2223local CANCEL_GC = " GC"
2324local CANCEL_SYSTEM = " SYSTEM"
2425local CANCEL_USER = " USER"
2526
27+ local sleepx do
28+ local SLEEP_BLOCK_SIZE = 5
29+
30+ -- create a 10yr timer only called with `premature` set. The callback will
31+ -- release a global semaphore to wake up sleeping threads
32+ local sema = assert (require (" ngx.semaphore" ).new ())
33+ assert (timer_at (10 * 365 * 24 * 60 * 60 , function ()
34+ sema :post (math.huge )
35+ end ))
36+
37+ --- A `sleep` function that exits early on system exit. The same as `ngx.sleep`
38+ -- except that it will be interrupted when the current worker starts exiting.
39+ -- @param delay same as `ngx.sleep()`; delay in seconds.
40+ -- @return results of `ngx.worker.exiting()`
41+ -- @usage if sleepx(5) then
42+ -- -- sleep was interrupted, exit now
43+ -- return nil, "exiting"
44+ -- end
45+ --
46+ -- -- do stuff
47+ function sleepx (delay )
48+ if type (delay ) ~= " number" then
49+ error (" Bad argument #1, expected number, got " .. type (delay ), 2 )
50+ end
51+
52+ if delay <= 0 then
53+ sleep (delay )
54+ return exiting ()
55+ end
56+
57+ -- this doesn't work
58+ -- see https://github.com/openresty/lua-resty-core/issues/337
59+ -- sema:wait(delay)
60+ -- return exiting()
61+
62+ -- fall-back to sleeping in SLEEP_BLOCK_SIZE sec chunks
63+ local t = now ()
64+ local exit_at = t + delay
65+ while exit_at > t and not exiting () do
66+ sleep (min (SLEEP_BLOCK_SIZE , exit_at - t ))
67+ t = now ()
68+ end
69+ return exiting ()
70+ end
71+ end
72+
2673
2774
2875--- Cancel the timer.
@@ -141,10 +188,7 @@ local function handler(premature, id)
141188 end
142189
143190 -- existing timer recurring, so keep this thread alive and just sleep
144- if not exiting () then
145- sleep (next_interval )
146- end
147- premature = exiting ()
191+ premature = sleepx (next_interval )
148192 end -- while
149193end
150194
340384return setmetatable (
341385 {
342386 new = new ,
387+ sleepx = sleepx ,
343388 CANCEL_GC = CANCEL_GC ,
344389 CANCEL_SYSTEM = CANCEL_SYSTEM ,
345390 CANCEL_USER = CANCEL_USER ,
0 commit comments