Author: SOFTINNOV / Nenad Rakocevic Date: 11/03/2005 Version: 1.0 Comments: firstname.lastname@example.org
Table of Contents
4. Task-master API
5. Task master settings
6. Module API
6.1. Module definition
6.4. Data exchange
UniServe is built on the single-process port multiplexing principle. It's a very efficient way to handle networks events, but it has its drawback : it's mono-process. This means that you are not allowed to write blocking code (like reading a big file from disk, waiting for some user inputs, etc...). In cases where you need to provide such features to your application while using UniServe to handle your network, you need to spawn a new REBOL process to handle your blocking code and then use an IPC (Inter-Process Communication) mechanism to make your processes work in cooperation.
The task-master service provides you an integrated framework to handle background tasks that need to be executed in a separate process. This service provides :
- External process management (spawning, killing).
- Communication with these processes (through asynchronous TCP channels).
- Easy and clean integration with your services (through custom events).
The task-master service needs the following files installed prior to its use :
These files are part of the UniServe archive. So you shouldn't need to do anything special to use this service.services/ task-master.r task-master/ task-handler.r
The task-master operates using the pre-forking model. When this service is started, it spawns a certain (user-settable) number of background REBOL processes. These processes once launched, connect automatically to the main UniServe process through the task-master TCP protocol and are registered by the service as ready to be used.
When you ask the task-master service to execute a job in the background, the service looks in an internal process list and takes the first not busy process and transfer your data to it with some additional contextual info.
When the job is completed, the process sends data back to the task-master service which dispatches the results to your services by calling the right events defined in your services.
If there are no free processes when a new job comes to the task-master, a new fresh process is started (if the max processes limit is not reached).
If the max number of process is reached, the jobs are stored in a waiting queue and assigned to a process as soon as it becomes available.
If the main UniServe process terminates, all the connected background processes will automatically quit too.
So the typical task-master usage from a service would look like :
All these properties, events and functions are explained in the following sections.install-service [ ... module: 'module-name ... on-received: ...[ ... shared/do-task some-data 'self ... ] ... on-task-done: func [data][ ... ] ... on-task-failed: func [reason][ ... ] ]
This section describes the properties, events and methods that the task-master service makes available for your services.
This property should be set in your service definition. It can be modified dynamically anywhere in your service.
Word Value Mandatory? Description module word! yes The default module name for background processing. This name should match exactly the name of the module file without the .r extension. (Watch out for case-sensitive filesystems)
You have to implement these events in your service definition to be able to process the results of background jobs.
Word Prototype Description on-task-done func [data [binary!]] Called when the background task has sent a response.
data : the response data from the module, (as formatted by the module response handler). data is cleared once the function is evaluated, so use 'copy if you want data to survive the function.
on-task-failed func [reason] Called when the background tasks failed.
reason : A value indicating the cause of the failure. The value is usually a word! but can be any other value returned by the module.
Failure codes The task-master provides the following internal error codes (the 'reason argument to 'on-task-failed) :
'error : a communication error with the background process occurred.'overload : all processes are busy, process limit reached and internal job waiting queue is full.
At load time, the task-master service installs the do-task function in UniServe's shared space, making it available to all services.
Word Prototype Description shared/do-task [data service /save locals] Launch a new job. This function is not blocking, so you can use it safely in event functions.
data : data to send to the background module.
service : reference to your services (usually just 'self).
/save : optionally saves your local client context.
locals : your client context (client/user-data).
Useful shortcuts I usually create a shortcut function for shared/do-task in my services. I'm using one of the following code:
or, if I need to save the client data :do-task: func [data][shared/do-task data self]
do-task: func [data /local cu][ cu: client/user-data shared/do-task/save data self context [ queue: cu/queue request: cu/request ] ]
You can change some startup settings for the task-master service. Currently you have to set these values directly in the task-master source code.
Word Value Mandatory? Description pool-start integer! yes Number of background processes when task-master starts (default: 2) pool-max integer! yes Maximum number of background processes (default: 4). job-max integer! yes Max size of the waiting jobs queue (default: 100). Jobs are queued when no processes are available and the process limit is reached.
A module is a REBOL script that implements the API provided by the task-handler framework. This module will be executed in a background process controlled by the task-master service from UniServe.
A new module has to be written in a new file with a name matching the module's name plus ".r" extension and it has to be located in the %modules folder in the UniServe archive.
Each module is defined using the install-module function. A REBOL header is required. (even if you leave it empty). A typical module's skeleton :
(NB: You do not need to 'do or 'load any scripts to use this function.)install-module [ name: 'module-name ... on-task-received: func [data][ ... response: ... ] ]
Word Value Mandatory? Description response any-type! yes The resulting data from the module execution, to be returned to the UniServe's caller service.
Word Prototype Description on-task-received func [data [string!]] Called when the process receives a new job to execute from the task-master.
data : The data sent by the calling service in molded format (can be any REBOL value).
You can exchange any kind of data between the caller service and the background module. The format is free and up to you. The task-master will mold the value passed to shared/do-task before sending it to the background process. In return, the task-master will deliver a binary molded version of the response value to the caller service (through the 'on-task-done event).
Try to keep the data exchanged as small as possible to save performance.