5 January 2002

## Using The SRE2003 Task Manager

Contents:

- Introduction
- Configuring
- The SRE_TASK procedure
- Details on SRE_TASK
- Examples of SRE_TASK
- Writing tasks in REXX

### Introduction

The SRE2003 task manager is a facility that simplifies the execution of non-request related tasks. For example, the task manager can be used to schedule recurring housekeeping tasks (such as cleaning up temporary storage), or to produce output that a client will obtain at a later date.

Running tasks is straightforward process of defining the task, and then launching instances of this task as needed (or scheduling instances to run a number of times). The main advantage of using the SRE2003 task manager, as opposed to a CRON like system utility, is that tasks can be easily launched by daemons, or by web based scripts.

Tasks can be any REXX program, or any executable that can be invoked by a REXX program. When one launches a task, you can provide it an argument (of any length).

The task manager also has resource utilization management capabilities. You can limit the number of tasks that can be running simultaneously, the lifespan of a task, and the frequency with which tasks can be launched. This control can be exercised on families of tasks, whose members can be freely defined.

Although flexible, the task manager has a sequential nature, which means that sometimes tasks will be queued up. Thus, the task manager should not be used to perform real-time resolution of web requests. However, it can be used to produce outputs (say, by a script that uses arguments provided via an html form) that can be delivered to the client at a later date.

For example, this can be as simple as saving a file in a web-accessible location, so that a client can (after a suitably long coffee break) request this output using a predetermined URL (one that points to this web-accessibe location). Alternatively, a client may (after a suitable wait) query an "output manager" script that will return the appropriate output (say, as indexed by the client's username).

To use the task manager, we strongly recommend using the SRE_TASK procedure. Basically, there are several types of actions supported by SRE_TASK:

1. defining a family (and setting a few parameters for this family)
2. requesting a task
3. obtaining current task status, and statistics on past tasks

### Configuring the Task Manager

There are a few parameters that can be modified to tweak the performance of the task manager. These are:

In SRE_TASK.RXX (in SRE2003's BIN subdirectory)

`DEFAULT_MAX_TASK=5` | The maximum number of simultaneous tasks that can be run simultaneously, defined across a family of tasks. Example: `DEFAULT_MAX_TASK=6`
`DEFAULT_MAX_LIFESPAN` | The default maximum lifespan of a task (in seconds), defined across a family of tasks. Example: `DEFAULT_MAX_LIFESPAN=1200`
`DEFAULT_MIN_WAIT` | The default minimum wait, in seconds, between launching tasks within the same family. 0 means "no limit". In other words, you can't launch a task until this many seconds have elapsed since the last task belonging to this family was launched. Example: `DEFAULT_MIN_WAIT=0`

In SRE2003.CFG
  The NO_TASKS parameter can be used to limit who can launch tasks. Basically:
  - 0 = disable the task manager
  - 1 = enable the task manager
  - 2 = the task manager is enabled when SRE2003 starts, but is disabled once the first request is recieved. This is useful if you just want to use an initialization procedure to launch a few (perhaps scheduled) tasks.
  See SRE2003.HTM for the details.

### Using SRE_TASK

The SRE_TASK procedure is used to control the task daemon.
Syntax: `astat=sre_task(action,name,controls,data,[ownid])`
where:

`ACTION` | The action to take. Four actions are recognized: `FAMILY` = define a family (and set some parameters) `DEFINE` = define a task (assign a task NAME to a rexx procedure), or remove an already defined task `LAUNCH` = launch a task `STATS` = compute some statistics `EXIST` = has a task, or family, been defined
`NAME` | NAME is a task name or a family name. The task name can also include a family name. Family names are case-insenstive, and must NOT contain spaces or periods. For example: `GIFMAKERS` `CLEANUPS` Task names are case-insensitive, and must NOT contain spaces or periods. For example: `BLINKING` `CLEAR_DELTAS` When including a family name in a task name, use a dot syntax of: `task_name.family_name` For example: `BLINKING.GIFMAKERS` `CLEAR_DELTAS.CLEANUP` When a task name is defined without a family name, it is assigned to the "generic" family. When a task name is defined with a family name that has NOT yet been defined, an error results and the request is ignored.
`CONTROLS` | CONTROLS is optional control information.
`DATA` | DATA is used to pass ACTION specific parameters.
`OWNID` | OWNID is strictly optional. It should be the "own id" of the calling procedure (say, as created with the SRE_DMN_OWN procedure). If an OWNID one is not available, SRE_TASK will create one.
astat will be a status message, or an error message. Error messages have the form: `error error-message`

### Details on SRE_TASK

The following details how to use SRE_TASK.

-   Action = `FAMILY` | This action is used to define families of tasks. Families are used to group tasks together, both as a means of specifying default parameters, and as a means of limiting the number of tasks that can be simultaneously running. It is okay to define a family that will contain only one task. CONTROLS may contain a comma seperated list of family specific limits: `MAX_TASK,MAX_LIFESPAN,MIN_WAIT` Notes on CONTROLS: If one (or more) of these is blank, the DEFAULT_ values are used for this family You can modify the family specific limits of an existing family by pre-pending `MODIFY` before `MAX_TASK,MAX_LIFESPAN,MIN_WAIT` Examples of CONTROLS:
    `not defined` | use defaults
    `10,100,0` | Max of 10 simultaneous tasks 100 second lifespan per task 0 seconds minimum wait
    `MODIFY 2,3600,120` | Modify the current parameters to be: Max of 2 simultaneous tasks 1 hour lifespan per task 2 minute minimum wait
With FAMILY, the DATA parameter is ignored. Notes on the return value: The return value from the `FAMILY` action of SRE_TASK is either: `a number > 0.` This signals successful definition of a family. The number is the total number of families now defined (including this one). `'error error_message'.` When the response starts with `error`, then some problem occurred, and the family was not defined. The `error_message` briefly describes the problem.
Action = `DEFINE` | DEFINE is used to define a task. Basically, this is used to associate a taskname with a file. When defining a taskname, use the `.FAMILY` to assign the taskname to a family. CONTROLS can be used to remove an already defined taskname. To do this, set controls=`REMOVE`, and do not specify the DATA argument. DATA must be a fully qualified filename of the REXX program of this task. Note: the return value from the `DEFINE` action of SRE_TASK is either: `two numbers > 0` (in a space delimited list). This signals successful definition (or removal) of a task. The first value is the number of tasks now defined, the second value is the total number of tasks now defined in this family. These values are after defining (or removing) this task. `'error error_message'.` When the response starts with `error`, then some problem occurred, and the family was not defined. The `error_message` briefly describes the problem.
  - Action=`LAUNCH` | Launch a task, using NAME to select a task-name (that has been defined using a prior DEFINE call). Remember to include a .FAMILY_NAME if needed. Two optional CONTROLS parameters are recognized: `SCHEDULE freq num_times` When included, this means run this task every freq days, stop running after num_times. `Freq` can be any positive decimal value, `num_times` can be any positive integer. Note that if you do not specify num_times, then there is no limit on the number of times the task will be launched. Note that when CONTROLS is used to schedule a task, the task will not run immediately -- its first execution will be at a scheduled time. Furthermore, the scheduled start-times may be off by a few minutes (the busier the task manager is, the more likely the start-time will be less precise).
    Examples: |
    `SCHEDULE 2` | repeat (indefinitely) every 48 hours
    `SCHEDULE 0.5 6` | repeat every 12 hours, do it 6 times
  `UNSCHEDULE` Unschedule any occurences of this task. Pending launchs are not removed (pending launches are previously scheduled launches of this task that have been put on hold due to wait-time or max-launch conditions). However, no more of these tasks will be launched. Note that UNSCHEDULE will unschedule any task with this NAME. This might include several tasks that were scheduled independently (perhaps by different calls to SRE_TASK, perhaps with different DATA parameters). Note: If you do not include any CONTROLS parameters, the task will be immediately launched. DATA is information that will be sent to the REXX program/procedure when it is launched. The program can read this using: `parse arg info,task_count` See Writing tasks in REXX for the details... The structure of the DATA is of no concern to the task manager -- it is up to the procedure requesting the task, and the task, to determine how to pass information effectively. Note: the return value from the LAUNCH action is a status message: For example:
        Launched  TASK_15 as SRE_TASK_107_1
        Scheduled: T3.F1
        Pending on min_wait
        Pending on max_task
        Launched  TASK_16 as SRE_TASK_107_2
        Scheduled: T2
In the `Launched` returns, the first word identifies the daemon-id of this instance of the task, the second word is the macrospace procedure containing the REXX code for this task.
Action = `STATS` | Return statistics on defined families, defined tasks, active tasks, scheduled tasks, and pending tasks. A simple set of HTML tables is returned. You can send these to a client using SRE_COMMAND('VAR ...')
Action = `EXIST` | Check on whether a family, or a task, has already been defined. The syntax is:
       astat=sre_task('EXIST','taskname.familyname')
`astat` will be: `0` : task (or family) exists `1` : family does not exist `2` : family exists, but no such task has been defined for this family To check that a family has been defined, use:
       astat=sre_task('EXIST','.familyname')
That is, have nothing befor the `.familyname`

### Examples of SRE_TASK

`astat=sre_task('FAMILY','GIFMAKERS')`
  Create a family with the name `GIFMAKERS`. Use the generic specifications.

`astat=sre_task('DEFINE','BLEND.GIFMAKERS',,'F:\SRE\SCRIPTS\BLEND_GIF.CMD')`
  Define a task to be referred to as `BLEND.GIFMAKERS`. This will be in the `GIFMAKERS` family. The REXX program for this task is `F:\SRE\SCRIPTS\BLEND_GIF.CMD`

`astat=sre_task('DEFINE','BLEND.GIFMAKERS','REMOVE')`
  Remove the BLEND.GIFMAKERS task. You can then reDEFINE BLEND.GIFMAKERS (say, using a new version of the REXX procedure file).

`astat=sre_task('LAUNCH','CLEANUP1','SCHEDULE 1 ','allfiles=Y&zip=A')`
  Schedule the CLEANUP1 task to run once a day, with the first instance being launched in one day. The string `allfiles=Y&zip=A` will be sent to the task each time that it is launched.

  Hint: to schedule a task that begins immediately, you can use two calls to sre_task. For example:
  `astat=sre_task('LAUNCH','CLEANUP1',,'allfiles=Y&zip=A')`
  `astat=sre_task('LAUNCH','CLEANUP1','SCHEDULE 1 ','allfiles=Y&zip=A')`

### Creating Tasks

The task manager is designed to execute REXX procedures. More precisely, the task manager will call tasks, where we define a task as:

> a REXX procedures that is loaded into macrospace, and called as an external procedure

As with other external procedures, the first line must be a REXX comment (`/* ... */`), and the first non-comment line should not be a procedure definition. That is, it should not start with
`my_proc_name:procedure`
(though it can start with just `my_proc_name:`)

Tasks will be passed two argument --

1. the contents of the DATA parameter of SRE_TASK.
2. For scheduled tasks, the count of times this task has been called.
   For non-scheduled tasks, this is not set (the parameter's value is ' ').

Tasks can also access the SRE2003 system variables, using the SRE_VALUE `SRE`, `GLOBAL`, and `SRESYS` enviroments. However, they can not (without serious hacking) access any request specific parameters. Thus, they should not use SRE_COMMAND, SRE_REQFIELD, and other such procedures.

When complete, tasks should return with a value of `1`. Actually, it doesn't matter what they return -- SRE2003 does not pay attention to what is `return`ed by tasks. However, they should `return` , rather then `exit`.

Notes:

- To read the arguments passed to it by the task manager, a task can use:
  `parse arg info,task_count`

- Actually actually, SRE2003 pays a little bit of attention to what is returned by a task -- it will save the first line of the return. You can read these returns (for the last hundred or so completed tasks) via the STATS option of SRE_TASK.

- Tasks should have a definitive beginning and end. They should not be resident. If you need a permanent daemon, use the SRE_DMN procedures, and launch it in an SRE2003 initialization procedure.

  Alternatively, to run your task a number of times over a defined period, you can use the SCHEDULE argument when launching a task.

- If a task should crash, it will have unpredictable impacts on SRE2003. Most of the time, the effects will be minor -- SRE2003 will eventually kill the thread in which the task is running. However, on occasion SRE2003 will kill a thread improperly, which can have unpredictable effects.

- Tasks can launch executable programs using the `address cmd` syntax. For example:
  `address cmd 'XCOPY D:\SRE2003\DELTAS\*.VX F:\BACKUP\V502'`