teal-src/prosody/plugins/mod_cron.tl
author Kim Alvefur <zash@zash.se>
Sat, 14 Oct 2023 22:32:33 +0200
changeset 13269 6ac5ad578565
parent 13268 9b720c38fee8
child 13273 d50bee584969
permissions -rw-r--r--
mod_cron: Load last task run time inside task runner to fix async This ensures that all interactions with storage happen inside an async thread, allowing async waiting to be performed in storage drivers.
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
11990
3d5135e8a2a7 mod_cron: Initial commit of periodic task runner
Kim Alvefur <zash@zash.se>
parents:
diff changeset
     1
module:set_global();
3d5135e8a2a7 mod_cron: Initial commit of periodic task runner
Kim Alvefur <zash@zash.se>
parents:
diff changeset
     2
12983
fbbf4f0db8f0 teal: Move into prosody namespace
Kim Alvefur <zash@zash.se>
parents: 12507
diff changeset
     3
local async = require "prosody.util.async";
fbbf4f0db8f0 teal: Move into prosody namespace
Kim Alvefur <zash@zash.se>
parents: 12507
diff changeset
     4
local datetime = require "prosody.util.datetime";
11990
3d5135e8a2a7 mod_cron: Initial commit of periodic task runner
Kim Alvefur <zash@zash.se>
parents:
diff changeset
     5
3d5135e8a2a7 mod_cron: Initial commit of periodic task runner
Kim Alvefur <zash@zash.se>
parents:
diff changeset
     6
local record map_store<K,V>
3d5135e8a2a7 mod_cron: Initial commit of periodic task runner
Kim Alvefur <zash@zash.se>
parents:
diff changeset
     7
	-- TODO move to somewhere sensible
3d5135e8a2a7 mod_cron: Initial commit of periodic task runner
Kim Alvefur <zash@zash.se>
parents:
diff changeset
     8
	get : function (map_store<K,V>, string, K) : V
3d5135e8a2a7 mod_cron: Initial commit of periodic task runner
Kim Alvefur <zash@zash.se>
parents:
diff changeset
     9
	set : function (map_store<K,V>, string, K, V)
3d5135e8a2a7 mod_cron: Initial commit of periodic task runner
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    10
end
3d5135e8a2a7 mod_cron: Initial commit of periodic task runner
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    11
3d5135e8a2a7 mod_cron: Initial commit of periodic task runner
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    12
local enum frequency
3d5135e8a2a7 mod_cron: Initial commit of periodic task runner
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    13
	"hourly"
3d5135e8a2a7 mod_cron: Initial commit of periodic task runner
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    14
	"daily"
12006
cbed7d8d8f35 mod_cron: Add a 'weekly' job frequency
Kim Alvefur <zash@zash.se>
parents: 12005
diff changeset
    15
	"weekly"
11990
3d5135e8a2a7 mod_cron: Initial commit of periodic task runner
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    16
end
3d5135e8a2a7 mod_cron: Initial commit of periodic task runner
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    17
3d5135e8a2a7 mod_cron: Initial commit of periodic task runner
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    18
local record task_spec
3d5135e8a2a7 mod_cron: Initial commit of periodic task runner
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    19
	id : string -- unique id
3d5135e8a2a7 mod_cron: Initial commit of periodic task runner
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    20
	name : string -- name or short description
3d5135e8a2a7 mod_cron: Initial commit of periodic task runner
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    21
	when : frequency
3d5135e8a2a7 mod_cron: Initial commit of periodic task runner
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    22
	last : integer
3d5135e8a2a7 mod_cron: Initial commit of periodic task runner
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    23
	run : function (task_spec, integer)
3d5135e8a2a7 mod_cron: Initial commit of periodic task runner
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    24
	save : function (task_spec, integer)
3d5135e8a2a7 mod_cron: Initial commit of periodic task runner
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    25
end
3d5135e8a2a7 mod_cron: Initial commit of periodic task runner
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    26
3d5135e8a2a7 mod_cron: Initial commit of periodic task runner
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    27
local record task_event
3d5135e8a2a7 mod_cron: Initial commit of periodic task runner
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    28
	source : module
3d5135e8a2a7 mod_cron: Initial commit of periodic task runner
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    29
	item : task_spec
3d5135e8a2a7 mod_cron: Initial commit of periodic task runner
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    30
end
3d5135e8a2a7 mod_cron: Initial commit of periodic task runner
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    31
12006
cbed7d8d8f35 mod_cron: Add a 'weekly' job frequency
Kim Alvefur <zash@zash.se>
parents: 12005
diff changeset
    32
local periods : { frequency : integer } = { hourly = 3600, daily = 86400, weekly = 7*86400 }
11990
3d5135e8a2a7 mod_cron: Initial commit of periodic task runner
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    33
3d5135e8a2a7 mod_cron: Initial commit of periodic task runner
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    34
local active_hosts : { string : boolean } = {  }
3d5135e8a2a7 mod_cron: Initial commit of periodic task runner
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    35
3d5135e8a2a7 mod_cron: Initial commit of periodic task runner
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    36
function module.add_host(host_module : moduleapi)
3d5135e8a2a7 mod_cron: Initial commit of periodic task runner
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    37
3d5135e8a2a7 mod_cron: Initial commit of periodic task runner
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    38
	local last_run_times = host_module:open_store("cron", "map") as map_store<string,integer>;
3d5135e8a2a7 mod_cron: Initial commit of periodic task runner
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    39
	active_hosts[host_module.host] = true;
3d5135e8a2a7 mod_cron: Initial commit of periodic task runner
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    40
3d5135e8a2a7 mod_cron: Initial commit of periodic task runner
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    41
	local function save_task(task : task_spec, started_at : integer)
3d5135e8a2a7 mod_cron: Initial commit of periodic task runner
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    42
		last_run_times:set(nil, task.id, started_at);
3d5135e8a2a7 mod_cron: Initial commit of periodic task runner
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    43
	end
3d5135e8a2a7 mod_cron: Initial commit of periodic task runner
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    44
13269
6ac5ad578565 mod_cron: Load last task run time inside task runner to fix async
Kim Alvefur <zash@zash.se>
parents: 13268
diff changeset
    45
	local function restore_task(task : task_spec)
6ac5ad578565 mod_cron: Load last task run time inside task runner to fix async
Kim Alvefur <zash@zash.se>
parents: 13268
diff changeset
    46
		if task.last == nil then
6ac5ad578565 mod_cron: Load last task run time inside task runner to fix async
Kim Alvefur <zash@zash.se>
parents: 13268
diff changeset
    47
			task.last = last_run_times:get(nil, task.id);
6ac5ad578565 mod_cron: Load last task run time inside task runner to fix async
Kim Alvefur <zash@zash.se>
parents: 13268
diff changeset
    48
		end
6ac5ad578565 mod_cron: Load last task run time inside task runner to fix async
Kim Alvefur <zash@zash.se>
parents: 13268
diff changeset
    49
	end
6ac5ad578565 mod_cron: Load last task run time inside task runner to fix async
Kim Alvefur <zash@zash.se>
parents: 13268
diff changeset
    50
11990
3d5135e8a2a7 mod_cron: Initial commit of periodic task runner
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    51
	local function task_added(event : task_event) : boolean
3d5135e8a2a7 mod_cron: Initial commit of periodic task runner
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    52
		local task = event.item;
3d5135e8a2a7 mod_cron: Initial commit of periodic task runner
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    53
		if task.name == nil then
3d5135e8a2a7 mod_cron: Initial commit of periodic task runner
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    54
			task.name = task.when;
3d5135e8a2a7 mod_cron: Initial commit of periodic task runner
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    55
		end
3d5135e8a2a7 mod_cron: Initial commit of periodic task runner
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    56
		if task.id == nil then
3d5135e8a2a7 mod_cron: Initial commit of periodic task runner
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    57
			task.id = event.source.name .. "/" .. task.name:gsub("%W", "_"):lower();
3d5135e8a2a7 mod_cron: Initial commit of periodic task runner
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    58
		end
13269
6ac5ad578565 mod_cron: Load last task run time inside task runner to fix async
Kim Alvefur <zash@zash.se>
parents: 13268
diff changeset
    59
		task.restore = restore_task;
11990
3d5135e8a2a7 mod_cron: Initial commit of periodic task runner
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    60
		task.save = save_task;
13269
6ac5ad578565 mod_cron: Load last task run time inside task runner to fix async
Kim Alvefur <zash@zash.se>
parents: 13268
diff changeset
    61
		module:log("debug", "%s task %s added", task.when, task.id);
11990
3d5135e8a2a7 mod_cron: Initial commit of periodic task runner
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    62
		return true;
3d5135e8a2a7 mod_cron: Initial commit of periodic task runner
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    63
	end
3d5135e8a2a7 mod_cron: Initial commit of periodic task runner
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    64
3d5135e8a2a7 mod_cron: Initial commit of periodic task runner
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    65
	local function task_removed(event : task_event) : boolean
3d5135e8a2a7 mod_cron: Initial commit of periodic task runner
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    66
		local task = event.item;
3d5135e8a2a7 mod_cron: Initial commit of periodic task runner
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    67
		host_module:log("debug", "Task %s removed", task.id);
3d5135e8a2a7 mod_cron: Initial commit of periodic task runner
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    68
		return true;
3d5135e8a2a7 mod_cron: Initial commit of periodic task runner
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    69
	end
3d5135e8a2a7 mod_cron: Initial commit of periodic task runner
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    70
3d5135e8a2a7 mod_cron: Initial commit of periodic task runner
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    71
	host_module:handle_items("task", task_added, task_removed, true);
3d5135e8a2a7 mod_cron: Initial commit of periodic task runner
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    72
3d5135e8a2a7 mod_cron: Initial commit of periodic task runner
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    73
	function host_module.unload()
3d5135e8a2a7 mod_cron: Initial commit of periodic task runner
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    74
		active_hosts[host_module.host]=nil;
3d5135e8a2a7 mod_cron: Initial commit of periodic task runner
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    75
	end
3d5135e8a2a7 mod_cron: Initial commit of periodic task runner
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    76
end
3d5135e8a2a7 mod_cron: Initial commit of periodic task runner
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    77
3d5135e8a2a7 mod_cron: Initial commit of periodic task runner
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    78
local function should_run(when : frequency, last : integer) : boolean
12190
7f25ac9d8f0d mod_cron: Allow for a small amount of timer drift
Kim Alvefur <zash@zash.se>
parents: 12006
diff changeset
    79
	return not last or last + periods[when]*0.995 <= os.time();
11990
3d5135e8a2a7 mod_cron: Initial commit of periodic task runner
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    80
end
3d5135e8a2a7 mod_cron: Initial commit of periodic task runner
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    81
3d5135e8a2a7 mod_cron: Initial commit of periodic task runner
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    82
local function run_task(task : task_spec)
13269
6ac5ad578565 mod_cron: Load last task run time inside task runner to fix async
Kim Alvefur <zash@zash.se>
parents: 13268
diff changeset
    83
	task:restore();
6ac5ad578565 mod_cron: Load last task run time inside task runner to fix async
Kim Alvefur <zash@zash.se>
parents: 13268
diff changeset
    84
	if not should_run(task.when, task.last) then
6ac5ad578565 mod_cron: Load last task run time inside task runner to fix async
Kim Alvefur <zash@zash.se>
parents: 13268
diff changeset
    85
		return;
6ac5ad578565 mod_cron: Load last task run time inside task runner to fix async
Kim Alvefur <zash@zash.se>
parents: 13268
diff changeset
    86
	end
11990
3d5135e8a2a7 mod_cron: Initial commit of periodic task runner
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    87
	local started_at = os.time();
3d5135e8a2a7 mod_cron: Initial commit of periodic task runner
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    88
	task:run(started_at);
12493
8b42575738f0 mod_cron: Fix recording last task run time #1751
Kim Alvefur <zash@zash.se>
parents: 12190
diff changeset
    89
	task.last = started_at;
11990
3d5135e8a2a7 mod_cron: Initial commit of periodic task runner
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    90
	task:save(started_at);
3d5135e8a2a7 mod_cron: Initial commit of periodic task runner
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    91
end
3d5135e8a2a7 mod_cron: Initial commit of periodic task runner
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    92
12502
c3e47a5dd30d util.async: Add Teal description file
Kim Alvefur <zash@zash.se>
parents: 12493
diff changeset
    93
local task_runner : async.runner_t<task_spec> = async.runner(run_task);
12507
ad49bb3a4780 mod_cron: Remove difference between teal version
Kim Alvefur <zash@zash.se>
parents: 12502
diff changeset
    94
scheduled = module:add_timer(1, function() : integer
11990
3d5135e8a2a7 mod_cron: Initial commit of periodic task runner
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    95
	module:log("info", "Running periodic tasks");
3d5135e8a2a7 mod_cron: Initial commit of periodic task runner
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    96
	local delay = 3600;
3d5135e8a2a7 mod_cron: Initial commit of periodic task runner
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    97
	for host in pairs(active_hosts) do
3d5135e8a2a7 mod_cron: Initial commit of periodic task runner
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    98
		module:log("debug", "Running periodic tasks for host %s", host);
3d5135e8a2a7 mod_cron: Initial commit of periodic task runner
Kim Alvefur <zash@zash.se>
parents:
diff changeset
    99
		for _, task in ipairs(module:context(host):get_host_items("task") as { task_spec } ) do
13269
6ac5ad578565 mod_cron: Load last task run time inside task runner to fix async
Kim Alvefur <zash@zash.se>
parents: 13268
diff changeset
   100
			task_runner:run(task);
11990
3d5135e8a2a7 mod_cron: Initial commit of periodic task runner
Kim Alvefur <zash@zash.se>
parents:
diff changeset
   101
		end
3d5135e8a2a7 mod_cron: Initial commit of periodic task runner
Kim Alvefur <zash@zash.se>
parents:
diff changeset
   102
	end
3d5135e8a2a7 mod_cron: Initial commit of periodic task runner
Kim Alvefur <zash@zash.se>
parents:
diff changeset
   103
	module:log("debug", "Wait %ds", delay);
3d5135e8a2a7 mod_cron: Initial commit of periodic task runner
Kim Alvefur <zash@zash.se>
parents:
diff changeset
   104
	return delay;
3d5135e8a2a7 mod_cron: Initial commit of periodic task runner
Kim Alvefur <zash@zash.se>
parents:
diff changeset
   105
end);
3d5135e8a2a7 mod_cron: Initial commit of periodic task runner
Kim Alvefur <zash@zash.se>
parents:
diff changeset
   106
3d5135e8a2a7 mod_cron: Initial commit of periodic task runner
Kim Alvefur <zash@zash.se>
parents:
diff changeset
   107
-- TODO measure load, pick a good time to do stuff