task scheduler #296

Parent #1Owner #361Flags readSource hellcore/hellcore.db

Aliases: task scheduler, scheduler

7 verbs · 19 properties · 3 children

Verbs

VerbSpecFlagsDefinerLines
_logthis none thisrxd#29616
_handle_errorthis none thisrxd#29619
_dothis none thisrxd#29632
_runthis none thisrxd#29650
_startthis none thisrxd#2968
recyclethis none thisrxd#2966
_readlogthis none thisrxd#2968

Properties

PropertyDefinerFlagsOwnerValue
help_msg#296rc#361
list of 19{"The task scheduler lets you set up things to run at specific frequencies.", "", "Don't mess with $scheduler itself, check out its children:", " - $daily (#404806) (.frequency == 86400)", " - $weekly (#428597) (.frequency == 604800)", " - $gamedaily (#59272) (.frequency = 10800)", " - half-hourly (#441325)", "", "Add a verb to any child of scheduler and it will be guaranteed to run once every .frequency (in seconds). (Just make sure your verb doesn't start with an underscore.) Each of the above objects is +w, which means anyone can put a verb on them. It will run with your permissions etc.", "", "WHAT WILL HAPPEN:", " - your verb will run next check, after it's added. (see .check_frequency, generally .frequency/24)", " - if it's successful and returns a list or string, it will be mailed to you", " - if it fails, a stack trace will be mailed to you, and you will feel bad", " - mail will include total execution time (in real seconds)", "", "ALSO:", " - :_readlog() will spam you with the recent activity on it. e.g., ;$daily:_readlog().", " - @addfeature #202600 (tasknet) to see the scheduler's logs live."}
frequency#296rc#3610
check_frequency#296rc#3613600
last_runs#296rc#361
list of 17{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
log#296rc#361{}
max_log_lines#296rc#361250
wait_between_tasks#296rc#36130
run_task#296rc#3610
log_to_net#296rc#361#365
aliases#1rc#361{"task scheduler", "scheduler"}
description#1rc#361<clear>
object_size#1r#29{7737, 1298434650}
hidden_verbs#1rc#361<clear>
phelp_msg#1rc#361<clear>
weight#1rc#361<clear>
owner_verbs#1rc#361<clear>
plural_name#1rc#361<clear>
client_image#1rc#361<clear>
listening#1rc#361<clear>

Ancestry

Ancestors (nearest first): #1 root

Children: #297 daily, #298 weekly, #304 gamedaily

Call graph

calls n296_1 #296:_handle_error n35_7 #35:english_time n296_1->n35_7 n296_0 #296:_log n296_1->n296_0 n103_31 #103:render_error n296_1->n103_31 n38_2 #38:send_message n296_1->n38_2 n296_2 #296:_do n296_2->n296_1 n296_2->n35_7 n296_2->n296_0 n296_2->n38_2 n20_47 #20:from_value n296_2->n20_47 n296_3 #296:_run n296_3->n35_7 n296_3->n296_0 n296_3->n296_2 n107_43 #107:tell n296_3->n107_43 n20_59 #20:name_and_number n296_3->n20_59 n296_4 #296:_start n45_26 #45:leaves_suspended n296_4->n45_26 n296_5 #296:recycle n1_1 #1:recycle n296_5->n1_1 n296_6 #296:_readlog n296_6->n107_43 n296_6->n20_59 n35_18 #35:abbrev_ctime n296_6->n35_18

Source

_log

Spec this none thisFlags rxdOwner #361Definer #296

Referenced by

Source

1"_log(...) => Write args to this.log";
2if (caller != this)
3raise(E_PERM);
4endif
5text = tostr(@args);
6log = {@this.log, {time(), text}};
7if (is_a(this.log_to_net, $net))
8fork (0)
9this.log_to_net:sys_announce(this.name, ": ", text);
10endfork
11endif
12if (length(log) > this.max_log_lines)
13this.log = log[1..this.max_log_lines];
14else
15this.log = log;
16endif

_handle_error

Spec this none thisFlags rxdOwner #361Definer #296

Referenced by

Source

1"_handle_error(STR verbname, THROWN e, INT elapsed_execution_secs, INT time_of_execution) => handle/log a broken task.";
2if (caller != this)
3raise(E_PERM);
4endif
5{v, e, elapsed, when} = args;
6{errcode, errmsg, value, stack} = e;
7elapsed_str = $time_utils:english_time(elapsed);
8this:_log("Got error ", toliteral(errcode), " from :", v, " after ", elapsed_str);
9{verbthis, verbname, verbprog, verbloc} = stack[1][1..4];
10"remove _do from stack";
11stack = stack[1..$ - 1];
12topline = tostr("'", errmsg, "' (", errcode, ") [value = ", value, "]");
13output = {topline, @$lu:map_arg($ansi, "strip", $rpg:render_error(errmsg, stack))};
14subj = tostr("ERR: Scheduled task on ", verbloc, " (:", verbname, ")");
15output = {@output, "", tostr("After ", elapsed_str, " of execution at ", ctime(when))};
16if (verbprog == #2)
17verbprog = #158;
18endif
19$mail_agent:send_message(this, verbprog, subj, output);

_do

Spec this none thisFlags rxdOwner #361Definer #296

Referenced by

Source

1"_do(verbname) => run task now.";
2if (caller != this)
3raise(E_PERM);
4endif
5{v} = args;
6fork (0)
7try
8start_time = time();
9ret = this:(v)();
10elapsed = time() - start_time;
11elapsed_str = $time_utils:english_time(elapsed);
12if ((typeof(ret) == STR) || (typeof(ret) == LIST))
13prog = verb_info(this, v)[1];
14if (prog == #2)
15prog = #158;
16endif
17subj = tostr("OK: Scheduled task on ", this, " (:", v, ")");
18if (typeof(ret) == LIST)
19text = $su:from_value(ret, 1, 10);
20else
21text = {ret};
22endif
23text = {"Returned: ", @text, ""};
24text = {@text, tostr("After ", elapsed_str, " of execution.")};
25$mail_agent:send_message(this, prog, subj, text);
26endif
27this:_log("Completed :", v, " in ", elapsed_str, " => ", $su:from_value(ret));
28except e (ANY)
29elapsed = time() - start_time;
30this:_handle_error(v, e, elapsed, start_time);
31endtry
32endfork

_run

Spec this none thisFlags rxdOwner #361Definer #296

Referenced by

none

Source

1"_run() => Check for tasks, repeat infinitely.";
2if (this.frequency < 60)
3player:tell(".frequency for ", $su:nn(this), " is invalid. Must be at LEAST 60 seconds.");
4return;
5endif
6if ((this.check_frequency < 15) || (this.check_frequency > (this.frequency / 2)))
7player:tell(".check_frequency for ", $su:nn(this), " is invalid. Must be >15 seconds, but no more than half of .frequency.");
8return;
9endif
10if (task_valid(this.run_task))
11if (valid(player))
12player:tell("A :_run task is already running for ", $su:nn(this), ". [Task ", this.run_task, "]");
13else
14"This is being run by the server (generally at start.)";
15endif
16return;
17endif
18if (!caller_perms().wizard)
19player:tell("You can't start this up, you have to be a wizard.");
20return;
21endif
22this.run_task = task_id();
23while (1)
24for v in (verbs(this))
25if (v[1] == "_")
26continue;
27endif
28do = 0;
29last_time = `this.last_runs[v] ! E_RANGE';
30if (last_time == E_RANGE)
31this:_log("Running :", v, " for the first time.");
32do = 1;
33else
34now = time();
35if ((last_time + this.frequency) < (now + this.check_frequency))
36since_last_str = $time_utils:english_time(now - last_time);
37this:_log("Running :", v, " -- last run ", since_last_str, " ago");
38do = 1;
39endif
40endif
41if (do)
42this:_do(v);
43this.last_runs[v] = time();
44suspend(this.wait_between_tasks);
45else
46yield;
47endif
48endfor
49suspend(this.check_frequency);
50endwhile

_start

Spec this none thisFlags rxdOwner #361Definer #296

Referenced by

none

Source

1if (caller != #0)
2raise(E_PERM);
3endif
4for c in ($ou:leaves_suspended($scheduler))
5fork (0)
6c:_run();
7endfork
8endfor

recycle

Spec this none thisFlags rxdOwner #361Definer #296

Referenced by

none

Source

1if (caller.wizard || (caller == this.owner))
2task_valid(this.run_task) && kill_task(this.run_task);
3return pass(@args);
4else
5return E_PERM;
6endif

_readlog

Spec this none thisFlags rxdOwner #361Definer #296

Referenced by

none

Source

1player:tell("-- Log for ", $su:nn(this), " --");
2for l in (this.log)
3{when, text} = l;
4when = $time_utils:abbrev_ctime(when);
5player:tell("[", when, "] ", text);
6yield;
7endfor
8player:tell("-- End of log --");