8.18 Server side scheduler

One of the problems that usually game developers face while programming on the server side is how to handle multiple timed events and delays. A typical example is implementing count-downs for multiple bombs that should explode, or doors that should open or close etc...

Both Java and ActionScript offer a few solutions for handling time tasks (like the Timer class or setInterval) but none of them is really effective when you need to handle many of these events. Additionally both mentioned tools run on top of Java threads and each instance will take 1 thread, leading to a possible performance degradation if the number of timed tasks grows in the hundreds.

An example of this is when multiple threads are handling timed events in a Room-Level extension. Supposing we're using 4 threads for each room, you can imagine how many threads we would end up with once the number of Rooms grows. Even with only 100 rooms the JVM will have 400 threads to deal with, which can already tax the overall server performance.

» The solution

SmartFoxServer 1.6 provides a specific set of classes that will help in handling multiple time events using a global class called Scheduler, which can handle as many events as you wish by using one single thread.

Creating a new timed task requires the following steps:

  1. Create a Task object, which can contain as many custom parameters as you wish describing the task to execute.
  2. Add the Task to the Scheduler specifying when this task should be executed.
  3. Create a callback handler (a method or function) which will be called by the Scheduler when it's time to execute the task

» An example

The following is a simple ActionScript extension which demonstrates the usage of the Scheduler object.
The source of this example is provided with SmartFoxServer 1.6 in the sfsExtensions/ folder

// We import the correct java package
var _scheduler = Packages.it.gotoandplay.smartfoxserver.util.scheduling

// Global variable
var scheduler = null

function init()
{
	trace(">>>>> Scheduler Test running ...")

	scheduler = new _scheduler.Scheduler()

	// Start the scheduler
	scheduler.startService()

	/*
	* The Task object describes the task to be executed
	* You can pass any object in the constructor, containing any custom parameters
	*/
	var task1 = new _scheduler.Task( {name:"have breakfast"} )
	var task2 = new _scheduler.Task( {name:"play videogames"} )
	var task3 = new _scheduler.Task( {name:"work a bit", start:"14:00", end:"17:00"} )

	/*
	* This is the object that handles the call-backs generated by the Scheduler
	* when it's time to execute the task.
	*
	* The object must implement a method called doTask which receives a Task object
	* as the argument.
	*/
	var handlerObj = {}
	handlerObj.count = 0
	handlerObj.doTask = function(task)
	{
		trace("Executing task: " + task.id.name)

		if (task.id.name == "play videogames")
		{
			this.count++
			trace("count = " + this.count)

			if (this.count == 2)
			{
				task.active = false
				trace("End of loop")
			}
		}

		else if (task.id.name == "work a bit")
		{
			trace("Start at: " + task.id.start + ", End at: " + task.id.end)
		}
	}

	// We create the call-back handler
	var taskHandler = new _scheduler.ITaskHandler( handlerObj )

	/*
	* Here we add the tasks to the scheduler
	* specifiying the delay interval (2nd param) in seconds
	* if the task loops (3rd param)
	* and the call-back handler (4th param)
	*/
	scheduler.addScheduledTask(task1, 3, false, taskHandler)
	scheduler.addScheduledTask(task2, 5, true, taskHandler)
	scheduler.addScheduledTask(task3, 4, false, taskHandler)
}

function destroy()
{
	// This method should always be called to shut down the Scheduler
	scheduler.destroy(null)
}


function handleRequest(cmd, params, user, fromRoom)
{
 	//
}


function handleInternalEvent(evt)
{
	//	
}

function handleInternalRequest( params )
{
	//
}
	

While most of the code is self explanatory the portion of code where the callback handler is created requires a few comments. The handler should implement a Java interface, called ITaskHandler, which looks like this:

public interface ITaskHandler
{
	public void doTask(Task task) throws Exception;
}
	

Even if you're not familiar with Java, "implementing an interface" simply means implementing the methods declared by the interface, so in this case doTask().
In order to do this in ActionScript we simply create a generic object, attach a function to it called doTask(), and finally pass the object while constructing a new ITaskHandler object.

For the complete documentation of the Scheduler classes please refer to the javadoc

 


doc index