Skip to content

Commit 56ca7f8

Browse files
committed
fix(sleep) use interruptible sleep function
1 parent 0dfc4c7 commit 56ca7f8

1 file changed

Lines changed: 51 additions & 5 deletions

File tree

lib/resty/timer.lua

Lines changed: 51 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ local anchor_registry = {}
1414
local gc_registry = setmetatable({},{ __mode = "v" })
1515
local timer_id = 0
1616
local now = ngx.now
17-
local sleep = ngx.sleep
17+
local ngx_sleep = ngx.sleep
1818
local exiting = ngx.worker.exiting
1919

2020
local KEY_PREFIX = "[lua-resty-timer]"
@@ -23,6 +23,54 @@ local CANCEL_GC = "GC"
2323
local CANCEL_SYSTEM = "SYSTEM"
2424
local CANCEL_USER = "USER"
2525

26+
local sleep do
27+
-- create a 10yr timer only called with `premature` set. The callback will
28+
-- release a global semaphore to wake up sleeping threads
29+
local sema = assert(require("ngx.semaphore").new())
30+
assert(timer_at(10*365*24*60*60, function()
31+
sema:post(math.huge)
32+
33+
-- TODO: remove the below log line, it's an ugly hack around semaphores
34+
-- not being released properly, an Openresty bug.
35+
-- See https://github.com/openresty/lua-resty-core/issues/337
36+
ngx.timer.at(0, function()
37+
ngx.log(ngx.WARN,"please ignore, just generating IO, see https://github.com/openresty/lua-resty-core/issues/337")
38+
end)
39+
end))
40+
41+
--- A `sleep` function that exits early on system exit. The same as `ngx.sleep`
42+
-- except that it will be interrupted when the current worker starts exiting.
43+
-- @param delay same as `ngx.sleep()`; delay in seconds.
44+
-- @return results of `ngx.worker.exiting()`
45+
-- @usage if sleep(5) then
46+
-- -- sleep was interrupted, exit now
47+
-- return nil, "exiting"
48+
-- end
49+
--
50+
-- -- do stuff
51+
function sleep(delay)
52+
if type(delay) ~= "number" then
53+
error("Bad argument #1, expected number, got " .. type(delay), 2)
54+
end
55+
56+
if delay <= 0 then
57+
ngx_sleep(delay)
58+
return exiting()
59+
end
60+
61+
local _, err = sema:wait(delay)
62+
if err == "timeout" then
63+
return false
64+
end
65+
66+
if err then
67+
ngx.log(ngx.ERR, "waiting for semaphore failed: ", err)
68+
end
69+
70+
return exiting()
71+
end
72+
end
73+
2674

2775

2876
--- Cancel the timer.
@@ -141,10 +189,7 @@ local function handler(premature, id)
141189
end
142190

143191
-- 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()
192+
premature = sleep(next_interval)
148193
end -- while
149194
end
150195

@@ -340,6 +385,7 @@ end
340385
return setmetatable(
341386
{
342387
new = new,
388+
sleep = sleep,
343389
CANCEL_GC = CANCEL_GC,
344390
CANCEL_SYSTEM = CANCEL_SYSTEM,
345391
CANCEL_USER = CANCEL_USER,

0 commit comments

Comments
 (0)