Software /
code /
prosody
Changeset
11961:542a9a503073
util.async: Add sleep() method with configurable scheduling backend
No scheduler set by default, so it will error (we plan to initialize it in
util.startup).
We wanted to avoid a hard dependency on util.timer (which in turn depends on
network backends, etc.), and we didn't add timer.sleep() because we didn't
want to add a hard dependency on util.async for things that don't need it.
author | Matthew Wild <mwild1@gmail.com> |
---|---|
date | Mon, 29 Nov 2021 14:11:24 +0000 |
parents | 11960:12a3c05aa12d |
children | 11962:9a70a543c727 |
files | spec/util_async_spec.lua util/async.lua |
diffstat | 2 files changed, 69 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- a/spec/util_async_spec.lua Mon Nov 29 02:13:45 2021 +0100 +++ b/spec/util_async_spec.lua Mon Nov 29 14:11:24 2021 +0000 @@ -615,4 +615,58 @@ assert.spy(r.watchers.error).was_not.called(); end); end); + + describe("#sleep()", function () + after_each(function () + -- Restore to default + async.set_schedule_function(nil); + end); + + it("should fail if no scheduler configured", function () + local r = new(function () + async.sleep(5); + end); + r:run(true); + assert.spy(r.watchers.error).was.called(); + + -- Set dummy scheduler + async.set_schedule_function(function () end); + + local r2 = new(function () + async.sleep(5); + end); + r2:run(true); + assert.spy(r2.watchers.error).was_not.called(); + end); + it("should work", function () + local queue = {}; + local add_task = spy.new(function (t, f) + table.insert(queue, { t, f }); + end); + async.set_schedule_function(add_task); + + local processed_item; + local r = new(function (item) + async.sleep(5); + processed_item = item; + end); + r:run("test"); + + -- Nothing happened, because the runner is sleeping + assert.is_nil(processed_item); + assert.equal(r.state, "waiting"); + assert.spy(add_task).was_called(1); + assert.spy(add_task).was_called_with(match.is_number(), match.is_function()); + assert.spy(r.watchers.waiting).was.called(); + assert.spy(r.watchers.ready).was_not.called(); + + -- Pretend the timer has triggered, call the handler + queue[1][2](); + + assert.equal(processed_item, "test"); + assert.equal(r.state, "ready"); + + assert.spy(r.watchers.ready).was.called(); + end); + end); end);
--- a/util/async.lua Mon Nov 29 02:13:45 2021 +0100 +++ b/util/async.lua Mon Nov 29 14:11:24 2021 +0000 @@ -11,6 +11,9 @@ return thread; end +-- Configurable functions +local schedule_task = nil; -- schedule_task(seconds, callback) + local function runner_from_thread(thread) local level = 0; -- Find the 'level' of the top-most function (0 == current level, 1 == caller, ...) @@ -118,6 +121,15 @@ end; end +local function sleep(seconds) + if not schedule_task then + error("async.sleep() is not available - configure schedule function"); + end + local wait, done = waiter(); + schedule_task(seconds, done); + wait(); +end + local runner_mt = {}; runner_mt.__index = runner_mt; @@ -272,4 +284,7 @@ runner = runner; wait = wait_for; -- COMPAT w/trunk pre-0.12 wait_for = wait_for; + sleep = sleep; + + set_schedule_function = function (new_schedule_function) schedule_task = new_schedule_function; end; };