Software / code / prosody
Comparison
plugins/mod_cron.lua @ 11986:3d5135e8a2a7
mod_cron: Initial commit of periodic task runner
A number of modules now have periodic tasks that need to run, e.g. for
cleaning out old messages or files. This has highlighted a need for
coordinating and optimizing scheduling of such tasks.
| author | Kim Alvefur <zash@zash.se> |
|---|---|
| date | Sun, 21 Nov 2021 15:50:36 +0100 |
| child | 11995:bbd3ac65640d |
comparison
equal
deleted
inserted
replaced
| 11985:3740cf7a66a3 | 11986:3d5135e8a2a7 |
|---|---|
| 1 module:set_global(); | |
| 2 | |
| 3 local async = require("util.async"); | |
| 4 | |
| 5 local periods = { hourly = 3600; daily = 86400 } | |
| 6 | |
| 7 local active_hosts = {} | |
| 8 | |
| 9 function module.add_host(host_module) | |
| 10 | |
| 11 local last_run_times = host_module:open_store("cron", "map"); | |
| 12 active_hosts[host_module.host] = true; | |
| 13 | |
| 14 local function save_task(task, started_at) last_run_times:set(nil, task.id, started_at); end | |
| 15 | |
| 16 local function task_added(event) | |
| 17 local task = event.item; | |
| 18 if task.name == nil then task.name = task.when; end | |
| 19 if task.id == nil then task.id = event.source.name .. "/" .. task.name:gsub("%W", "_"):lower(); end | |
| 20 if task.last == nil then task.last = last_run_times:get(nil, task.id); end | |
| 21 task.save = save_task; | |
| 22 module:log("debug", "%s task %s added, last run %s", task.when, task.id, | |
| 23 task.last and require("util.datetime").datetime(task.last) or "never"); | |
| 24 return true | |
| 25 end | |
| 26 | |
| 27 local function task_removed(event) | |
| 28 local task = event.item; | |
| 29 host_module:log("debug", "Task %s removed", task.id); | |
| 30 return true | |
| 31 end | |
| 32 | |
| 33 host_module:handle_items("task", task_added, task_removed, true); | |
| 34 | |
| 35 function host_module.unload() active_hosts[host_module.host] = nil; end | |
| 36 end | |
| 37 | |
| 38 local function should_run(when, last) return not last or last + periods[when] <= os.time() end | |
| 39 | |
| 40 local function run_task(task) | |
| 41 local started_at = os.time(); | |
| 42 task:run(started_at); | |
| 43 task:save(started_at); | |
| 44 end | |
| 45 | |
| 46 local task_runner = async.runner(run_task); | |
| 47 module:add_timer(1, function() | |
| 48 module:log("info", "Running periodic tasks"); | |
| 49 local delay = 3600; | |
| 50 for host in pairs(active_hosts) do | |
| 51 module:log("debug", "Running periodic tasks for host %s", host); | |
| 52 for _, task in ipairs(module:context(host):get_host_items("task")) do | |
| 53 module:log("debug", "Considering %s task %s (%s)", task.when, task.id, task.run); | |
| 54 if should_run(task.when, task.last) then task_runner:run(task); end | |
| 55 end | |
| 56 end | |
| 57 module:log("debug", "Wait %ds", delay); | |
| 58 return delay | |
| 59 end); |