- Introduction
- Task Function Signature
- Task Function Parameters
- Returning a Task Status
- Performance
- Managing Task Time Slot
- Task Props
- Code Examples
Tasks
Introduction
Tasks in CET are callback functions with a fixed signature that belong to a task scheduler. For a high level overview of tasks, see the overview.
Task Function Signature
Tasks have a fixed function signature which receives the task object, the time-slot as well as the argument given to the scheduler.
public taskStatus myTask(Task task, timespan slot, Object arg) {..}
Task Function Parameters
Parameter | Description |
---|---|
Task task |
The object which represents this task in the task scheduler. |
timespan slot |
The time-slot given for this task to run within. |
Object arg |
The argument provided to the scheduler along with this task. |
Returning a Task Status
The return type taskStatus
is an enum
which communicates a requested state to the scheduler.
Task Status | Description |
---|---|
taskStatus.terminate |
The task requests to exit the scheduler. |
taskStatus.sleep |
The task requests the scheduler to ignore it for a period of time. |
taskStatus.run |
The task requests to continue running as soon as possible. |
Performance
Background tasks in CET do not run in parallel with the main loop. Instead, tasks run as a step of the main loop. Due to this, tasks overly prioritized, or managed incorrectly will degrade the user experience. Each task has a time-slot in which it must either complete its work or request to continue running during the next allotted time-slot.
Managing Task Time Slot
A time-slot is a timespan
value representing the amount of time a task has to complete its work. If the task doesn't complete its work within the time-slot provided, then it has overshot its time-slot. The scheduler will remove any task which overshoots its time-slot more than the allowed number of times, and will inform the user of the removal of the task.
In practice, tasks respect their time-slot by keeping track of the amount of time they've spent working, then comparing that to the time-slot's duration. If the task has spent more time working than the time-slot's duration, then the task should return the appropriate taskStatus
to the scheduler.
The function microTime()
retrieves the current time since CET started.
double startTime = microTime();
If a task has a loop it should check the time-slot's duration at the beginning of iterating as shown below. If the task has spent more time than the time-slot allows, then it should also return the appropriate task status.
{ int[] items = [1, 2, 3, 4, 5]; int start = microTime(); // Capture the time when the task started. for (item in items) { // "microTime() - start" calculates the time spent working. if (microTime() - start > slot.microseconds) // Outside of time-slot, return the appropriate task status // Usually taskStatus.sleep or taskStatus.run return taskStatus.run; } //Do work for this iteration } }
Task Props
The Task
object has a str->Object
map called props
. This map is persistent between runs of a task and is useful for tasks which need to keep track of state between more than one run.
The put(..)
method on Task
will add a key-value pair to the props map.
exampleTask.put("myKey", 0); // Store 0 under the key "myKey"
The get(..)
method on Task
will retrieve a value from the props map.
exampleTask.get("myKey"); // Retrieve the value under "myKey"
Code Examples
- A task which iterates a fixed number of times corresponding to its argument, is resumable, and which respects its time-slot.
/** * An example task which can resume from its last state * and checks its time-slot. */ public taskStatus exampleTask(Task task, timespan slot, Object arg) { if (arg as Int) { double start = microTime(); // Capture the time when the task started. int cycles = arg.v; if (!task.get("startIndex")) { // If the task doesn't have a start index, then set it to 0. task.put("startIndex", 0); } // Get the previous start index from the task's props. int startIndex = task.get("startIndex").?Int.v; // Loop through the array of items. The loop will start at the start index. for (i in startIndex..cycles) { // Check if the task has spent more time than the time-slot allows. if (microTime() - start > slot.microseconds) { // Store the last index in the task's props; task.put("startIndex", i); // Return run to tell the scheduler to continue running this task. return taskStatus.run; } // Do work for this iteration } } // Task completed or argument was not an integer. task.put("startIndex", null); // Return terminate to request removal from the scheduler. return taskStatus.terminate; }
- Creating a task which sleeps itself when needed.
/** * An example task which sleeps for at least 60 seconds before running again. */ public taskStatus exampleSleepingTask(Task task, timespan slot, Object arg) { str result = // Make server request; if (result = "complete") { // Remote work has completed, terminate this task. return taskStatus.terminate; } else if (result = "incomplete") { // Remote work is incomplete, sleep this task. return taskStatus.sleep; } // No valid server response, sleep again. return taskStatus.sleep; } { // Add the task to the idle scheduler with a 60 second sleep time. idleTasks.add("Example Sleeping Task", function exampleSleepingTask, sleep=timespan(seconds=60)); }
Comments
0 comments
Please sign in to leave a comment.