Timers - Mini-IT/SnipeWiki GitHub Wiki
The Snipe server platform has three different timer types for running recurring tasks. The cache server timer runs on the cache server in a separate thread, that is used both for counting the time and running the tasks. The slave server timers run on specific slave server instances, also in separate threads. The tasks can run both in a separate timer thread, or in a main execution thread. The third timer, so-called client timer, is located on every slave server and does not have a separate thread. It uses client requests for checking the timeouts and running the tasks. If a particular client does not do any requests, the task will never be triggered (the server will disconnect this client after 3 minutes). Since the execution triggers are client requests, you cannot guarantee the exact time when the task will run but instead you gain the advantage of the work spread over time automatically and possibly even over multiple slave servers.
The cache server timer is located in snipe.cache.TimerCache
class. It has a separate thread for running work. The thread checks for task execution once per second and executes the tasks one by one. You can add a new task with TimerCache.add()
method. Here's the full example (cache server module):
var _topUsers: List<{ id: Int, name: String }>;
public function new(s: CacheServerTest)
{
super(s);
// ...
server.timer.add({
name: 'Top Users',
method: runSaveTop,
time: 60,
dontLog: true
});
}
function runSaveTop()
{
_acquire();
var str = haxe.Json.stringify(_topUsers);
_release();
server.query("UPDATE TopUsers SET Params = " + server.quote(str));
}
In this example the users top is saved into database table once per minute. Note that we lock the JSON encoding operation in case the top is modified by a concurrent call from one of the slave server threads.
The slave server timer is located in snipe.slave.Timer
class. Just like the cache server timer, it runs in a separate thread. The thread checks for task execution once per second and executes the tasks one by one. The task execution can be either done in timer thread or moved back into the main thread. You can add a new task with the Timer.add()
method. Here's the full example (slave server module):
public function new(srv: ServerTest)
{
super(srv);
// ...
server.timer.add({
name: "Auto-finish old battles",
method: runFinishOld,
time: 60,
isServerThread: true,
dontLog: false
});
}
function runFinishOld()
{
for (battle in manager._list)
battle.checkFinishOld();
}
In this example, the slave server checks for old battles once per minute and finishes them if the timeout is reached. Note the "isServerThread" parameter. When it is set to true, the task method will be running in the main server thread.
The client timers are located on slave servers and set up in such way that their tasks run after the client requests handling if the timeout is reached. That way we can spread the work in time for each client without having usage spikes produced by the usual timer. Keep in mind that if the client does not send any requests, this timer will not do any work. By default, the clients will be disconnected if no messages were received from them for 3 minutes.
The client timer uses the snipe.slave.ClientTimer
class. You can add new tasks with ClientTimer.add()
method. Here's the example taken from the core user effects module:
public function new(srv: Server)
{
super(srv);
// ...
server.clientTimer.add({
name: "core/effect.runCheck",
method: this.runCheck,
time: 2,
log: false
});
}
function runCheck(c: ClientGame)
{
if (c.user.effects.hasEffects())
c.user.effects.check();
}
In this example, the timer checks for any finished user effects every two seconds.