chap-scheduler-conf.xml revision 006579fc6d904d79ff1065cc8aa5c244a00f41ab
<?xml version="1.0" encoding="UTF-8"?>
<!--
! CCPL HEADER START
!
! This work is licensed under the Creative Commons
! Attribution-NonCommercial-NoDerivs 3.0 Unported License.
! To view a copy of this license, visit
! or send a letter to Creative Commons, 444 Castro Street,
! Suite 900, Mountain View, California, 94041, USA.
!
! You can also obtain a copy of the license at
! See the License for the specific language governing permissions
! and limitations under the License.
!
! If applicable, add the following below this CCPL HEADER, with the fields
! enclosed by brackets "[]" replaced with your own identifying information:
! Portions Copyright [yyyy] [name of copyright owner]
!
! CCPL HEADER END
!
! Copyright 2011-2012 ForgeRock AS
!
-->
<chapter xml:id='chap-scheduler-conf'
xmlns='http://docbook.org/ns/docbook'
version='5.0' xml:lang='en'
xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
xsi:schemaLocation='http://docbook.org/ns/docbook http://docbook.org/xml/5.0/xsd/docbook.xsd'
xmlns:xlink='http://www.w3.org/1999/xlink'
xmlns:xinclude='http://www.w3.org/2001/XInclude'>
<title>Scheduling Tasks and Events</title>
<indexterm>
<primary>Scheduler</primary>
</indexterm>
<indexterm>
<primary>Scheduling tasks</primary>
</indexterm>
<para>OpenIDM enables you to schedule reconciliation and synchronization
tasks. You can also use scheduling to trigger scripts, collect and run
reports, trigger workflows, perform custom logging, and so forth.</para>
<para>OpenIDM supports <command>cron</command>-like syntax to schedule events
and tasks, based on expressions supported by the Quartz Scheduler (bundled
with OpenIDM).</para>
<para>If you use configuration files to schedule tasks and events, you must
By convention, OpenIDM uses file names of the form
<filename>schedule-<replaceable>schedule-name</replaceable>.json</filename>,
where <replaceable>schedule-name</replaceable> is a logical name for the
scheduled operation, for example,
There are several example schedule configuration files in the
<para>You can configure OpenIDM to pick up changes to scheduled tasks and
events dynamically, during initialization and also at runtime. For more
information, see <link xlink:href="integrators-guide#when-configuring-notes"
Configuration</citetitle></link>.</para>
<para>In addition to the fine-grained scheduling facility, you can perform a
scheduled batch scan for a specified date in OpenIDM data, and then
automatically execute a task when this date is reached. For more information,
see <xref linkend="task-scanner"/>.</para>
<section xml:id="scheduler-configuration-file">
<title>Scheduler Configuration</title>
<indexterm>
<primary>Scheduler</primary>
<secondary>Configuration</secondary>
</indexterm>
<itemizedlist>
<para>Schedules are configured through JSON objects. The schedule
configuration involves two types of files:</para>
that configures the overall scheduler service</para></listitem>
<replaceable>schedule-name</replaceable>.json</filename> file for each
configured schedule.</para></listitem>
</itemizedlist>
<para>The scheduler service configuration file
<programlisting language='javascript'>
{
"threadPool" : {
"threadCount" : "10"
},
"scheduler" : {
"instanceId" : "scheduler-example"
},
"advancedProperties" : {
"org.quartz.scheduler.instanceName" : "OpenIDMScheduler"
}
}
</programlisting>
<itemizedlist>
to the configuration of the Quartz Scheduler.</para>
<listitem><para><literal>threadCount</literal> specifies the maximum number
of threads that are available for the concurrent execution of scheduled
tasks.</para>
</listitem>
<listitem><para><literal>instanceID</literal> can be any string, but must be
unique for all schedulers working as if they are the same 'logical' Scheduler
within a cluster.</para></listitem>
<listitem><para><literal>advancedProperties</literal> (optional) enables you
to configure additional properties for the Quartz Scheduler.</para></listitem>
</itemizedlist>
<para>For details of all the configurable properties for the Quartz Scheduler,
see the <link xlink:show="new"
><citetitle>Quartz Scheduler Configuration Reference</citetitle></link>.</para>
<replaceable>schedule-name</replaceable>.json</filename> has the following
format:</para>
<programlisting language="javascript">
{
"enabled" : true,
"persisted" : false,
"type" : "cron",
"startTime" : "<replaceable>(optional) time</replaceable>",
"endTime" : "<replaceable>(optional) time</replaceable>",
"schedule" : "<replaceable>cron expression</replaceable>",
"misfirePolicy" : "<replaceable>optional, string</replaceable>",
"timeZone" : "<replaceable>(optional) time zone</replaceable>",
"invokeService" : "<replaceable>service identifier</replaceable>",
"invokeContext" : "<replaceable>service specific context info</replaceable>"
}</programlisting>
<variablelist>
<para>The schedule configuration properties are defined as follows:</para>
<varlistentry>
<term>enabled</term>
<listitem>
<para>Set to <literal>true</literal> to enable the schedule. When this
property is set to <literal>false</literal>, OpenIDM considers the
schedule configuration dormant, and does not allow it to be triggered or
executed.</para>
<para>If you want to retain a schedule configuration, but do not want it
used, set <literal>enabled</literal> to <literal>false</literal> for task
and event schedulers, instead of changing the configuration or
<command>cron</command> expressions.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>persisted (optional)</term>
<listitem>
<para>Specifies whether the schedule state should be persisted or stored
in RAM. Boolean (<literal>true</literal> or <literal>false</literal>),
<literal>false</literal> by default. For more information, see
<xref linkend="persistent-schedules"/>.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>type</term>
<listitem>
<para>Currently OpenIDM supports only <literal>cron</literal>.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>startTime (optional)</term>
<listitem>
<para>Used to start the schedule at some time in the future. If this
parameter is omitted, empty, or set to a time in the past, the task or
event is scheduled to start immediately.</para>
<para>Use ISO 8601 format to specify times and dates (<literal><replaceable>
YYYY</replaceable>-<replaceable>MM</replaceable>-<replaceable>DD
</replaceable>T<replaceable>hh</replaceable>:<replaceable>mm
</replaceable>:<replaceable>ss</replaceable></literal>).</para>
</listitem>
</varlistentry>
<varlistentry>
<term>endTime (optional)</term>
<listitem>
<para>Used to plan the end of scheduling.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>schedule</term>
<listitem>
<para>Takes <command>cron</command> expression syntax. For more information,
see the <link xlink:show="new"
><citetitle>CronTrigger Tutorial</citetitle></link> and <link
xlink:show="new"><citetitle>Lesson 6: CronTrigger</citetitle></link>.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>misfirePolicy (optional)</term>
<listitem>
<para>For persistent schedules, specifies the behavior if the scheduled
task is missed, for some reason. Possible values are as follows:
</para>
<itemizedlist>
<listitem><para><literal>fireAndProceed</literal>. The first execution
of a missed schedule is immediately executed when the server is back
online. Subsequent executions are discarded. After this, the normal
schedule is resumed.</para></listitem>
<listitem><para><literal>doNothing</literal>, all missed schedules are
discarded and the normal schedule is resumed when the server is back
online.</para></listitem>
</itemizedlist>
</listitem>
</varlistentry>
<varlistentry>
<term>timeZone (optional)</term>
<listitem>
<para>If not set, OpenIDM uses the system time zone.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>invokeService</term>
<listitem>
<para>Defines the type of scheduled event or action. The value of this
parameter can be one of the following:</para>
<itemizedlist>
<listitem><para><literal>"sync"</literal> for reconciliation</para></listitem>
<listitem><para><literal>"provisioner"</literal> for LiveSync</para></listitem>
<listitem><para><literal>"script"</literal> to call some other scheduled
operation defined in a script</para></listitem>
</itemizedlist>
</listitem>
</varlistentry>
<varlistentry>
<term>invokeContext</term>
<listitem>
<para>Specifies contextual information, depending on the type of scheduled
event (the value of the <literal>invokeService</literal> parameter).
</para>
<para>The following example invokes reconciliation.</para>
<programlisting language="javascript">
{
"invokeService": "sync",
"invokeContext": {
"action": "reconcile",
"mapping": "systemLdapAccount_managedUser"
}
}</programlisting>
<itemizedlist>
<para>For a scheduled reconciliation task, you can define the mapping
in one of two ways:</para>
<listitem>
as shown in the previous example. The mapping must exist in the
<listitem>
<para>Add the mapping definition inline by using the
<literal>"mapping"</literal> property, as shown in the example in
<link xlink:href="integrators-guide#alternative-mapping"
Mappings</citetitle></link>.</para>
</listitem>
</itemizedlist>
<para>The following example invokes a LiveSync action.</para>
<programlisting language="javascript">
{
"invokeService": "provisioner",
"invokeContext": {
"action": "liveSync",
}
}</programlisting>
<para>For scheduled LiveSync tasks, the <literal>"source"</literal> property
follows OpenIDM's convention for a pointer to an external resource object
and takes the form <literal>system/<replaceable>resource-name</replaceable>
/<replaceable>object-type</replaceable></literal>.</para>
<para>The following example invokes a script, which prints the string
<literal>Hello World</literal> to the OpenIDM log
<programlisting language="javascript">
{
"invokeService": "script",
"invokeContext": {
"script": {
"type": "text/javascript",
"source": "java.lang.System.out.println('Hello World’);"
},
}
}</programlisting>
<para>Note that these are sample configurations only. Your own schedule
configuration will differ according to your specific requirements.</para>
</listitem>
</varlistentry>
</variablelist>
</section>
<section xml:id="persistent-schedules">
<title>Configuring Persistent Schedules</title>
<para>By default, scheduling information, such as schedule state and details
of the schedule execution, is stored in RAM. This means that such
information is lost when OpenIDM is rebooted. The schedule configuration
<replaceable>schedule-name</replaceable>.json</filename> file) is not lost
when OpenIDM is shut down, and normal scheduling continues when the server is
restarted. However, there are no details of missed schedule executions that
should have occurred during the period the server was unavailable.</para>
<para>You can configure schedules to be persistent, which means that the
scheduling information is stored in the internal repository rather than in
RAM. With persistent schedules, scheduling information is retained when OpenIDM
is shut down. Any previously scheduled jobs can be rescheduled automatically
when OpenIDM is restarted.</para>
<para>Persistent schedules also enable you to manage scheduling across a
cluster (multiple OpenIDM instances). When scheduling is persistent, a
particular schedule will be executed only once across the cluster, rather than
once on every OpenIDM instance. For example, if your deployment includes a
cluster of OpenIDM nodes for high availability, you can use persistent
scheduling to start a reconciliation action on only one node in the cluster,
instead of starting several competing reconciliation actions on each node.</para>
<para>You can use persistent schedules with the default OrientDB repository,
or with the MySQL repository (see <link xlink:href="install-guide#chap-repository"
Repository For Production</citetitle></link>).
</para>
<para>To configure persistent schedules, set the <literal>"persisted"</literal>
property to <literal>true</literal> in the schedule configuration file
(<filename>schedule-<replaceable>schedule-name</replaceable>.json)</filename>.
</para>
<para>If OpenIDM is down when a scheduled task was set to occur, one or more
executions of that schedule might be missed. To specify what action should be
taken if schedules are missed, set the <literal>misfirePolicy</literal> in the
schedule configuration file. The <literal>misfirePolicy</literal> determines
what OpenIDM should do if scheduled tasks are missed. Possible values are as
follows:
</para>
<itemizedlist>
<listitem><para><literal>fireAndProceed</literal>. The first execution of
a missed schedule is immediately executed when the server is back online.
Subsequent executions are discarded. After this, the normal schedule is
resumed.</para></listitem>
<listitem><para><literal>doNothing</literal>. All missed schedules are
discarded and the normal schedule is resumed when the server is back
online.</para></listitem>
</itemizedlist>
</section>
<section xml:id="scheduler-examples">
<title>Schedule Examples</title>
<indexterm>
<primary>Schedule</primary>
<secondary>Examples</secondary>
</indexterm>
<para>The following example shows a schedule for reconciliation that
is not enabled. When enabled (<literal>"enabled" : true,</literal>),
reconciliation runs every 30 minutes, starting on the hour.</para>
<programlisting language="javascript">
{
"enabled": false,
"persisted": false,
"type": "cron",
"invokeService": "sync",
"invokeContext": {
"action": "reconcile",
"mapping": "systemLdapAccounts_managedUser"
}
}</programlisting>
<para>The following example shows a schedule for LiveSync enabled to run
every 15 seconds, starting at the beginning of the minute. The schedule is
persisted, that is, stored in the internal repository rather than in memory.
If one or more LiveSync executions are missed, as a result of OpenIDM being
unavailable, the first execution of the LiveSync action is executed when the
server is back online. Subsequent executions are discarded. After this, the
normal schedule is resumed.</para>
<programlisting language="javascript">
{
"enabled": false,
"persisted": true,
"misfirePolicy" : "fireAndProceed",
"type": "cron",
"invokeService": "provisioner",
"invokeContext": {
"action": "liveSync",
}
}</programlisting>
</section>
<section xml:id="check-quartz-updates">
<title>Checking For Quartz Updates</title>
<para>The Quartz Scheduler can check for updates over the Internet on the
Quartz project website, and report available updates in the OpenIDM log.
By default, this option is turned off, and should remain off in
production.</para>
<literallayout class="monospaced">system.properties:org.quartz.scheduler.skipUpdateCheck = true</literallayout>
</section>
<section xml:id="scheduler-service-implementations">
<title>Service Implementer Notes</title>
<para>Services that can be scheduled implement
<literal>ScheduledService</literal>. The service PID is used as a basis for
the service identifier in schedule definitions.</para>
</section>
<section xml:id="task-scanner">
<title>Scanning Data to Trigger Tasks</title>
<para>In addition to the fine-grained scheduling facility described
previously, OpenIDM provides a task scanning mechanism. The task scanner
enables you to perform a batch scan for a specified date in OpenIDM data,
on a scheduled interval, and then to execute a task when this date is
reached. When the task scanner identifies a condition that should trigger the
task, it can invoke a script created specifically to handle the task.</para>
objects for a "sunset date" and can invoke a script that executes a sunset
task on the user object when this date is reached.</para>
<section xml:id="task-scanner-config">
<title>Configuring the Task Scanner</title>
<para>The task scanner is essentially a scheduled task that queries a span of
managed users. The task scanner is configured in the same way as a regular
scheduled task, in a schedule configuration file named
(<filename>schedule-<replaceable>task-name</replaceable>.json)</filename>,
with the <literal>"invokeService"</literal> parameter set to
<literal>"taskscanner</literal>. The <literal>"invokeContext"</literal>
parameter defines the details of the scan, and the task that should be
executed when the specified condition is triggered.</para>
<para>The following example defines a scheduled scanning task that triggers
a sunset script. This sample configuration file is provided in the OpenIDM
delivery as
directory.</para>
<programlisting language="javascript">
{
"enabled" : true,
"type" : "cron",
"schedule" : "0 0 * * * ?",
"invokeService" : "taskscanner",
"invokeContext" : {
"waitForCompletion" : false,
"maxRecords" : 2000,
"numberOfThreads" : 5,
"scan" : {
"_queryId" : "scan-tasks",
"condition" : {
"before" : "${Time.now}"
},
"taskState" : {
"started" : "sunset/task-started",
"completed" : "sunset/task-completed"
},
"recovery" : {
"timeout" : "10m"
}
},
"task" : {
"script" : {
"type" : "text/javascript",
}
}
}
}</programlisting>
<variablelist>
<para>The <literal>"invokeContext"</literal> parameter takes the following
properties:
</para>
<varlistentry>
<term><literal>"waitForCompletion"</literal> (optional)</term>
<listitem>
<para>This property specifies whether the task should be performed
synchronously. Tasks are performed asynchronously by default (with
<literal>waitForCompletion</literal> set to false). A task ID (such as
<literal>{"_id":"354ec41f-c781-4b61-85ac-93c28c180e46"}</literal>) is
returned immediately. If this property is set to true, tasks are performed
synchronously and the ID is not returned until all tasks have completed.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>"maxRecords"</literal> (optional)</term>
<listitem>
<para>The maximum number of records that can be processed. This property
is not set by default so the number of records is unlimited. If a maximum
number of records is specified, that number will be spread evenly over the
number of threads.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>"numberOfThreads"</literal> (optional)</term>
<listitem>
<para>By default, the task scanner runs in a multi-threaded manner, that
is, numerous threads are dedicated to the same scanning task run.
Multithreading generally improves the performance of the task scanner. The
default number of threads for a single scanning task is ten. To change this
default, set the <literal>"numberOfThreads"</literal> property.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>"scan"</literal></term>
<listitem>
<para>Defines the details of the scan. The following properties are
defined:</para>
<variablelist>
<varlistentry>
<term><literal>"object"</literal></term>
<listitem>
<para>Defines the object type against which the query should be
performed.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>"_queryId"</literal></term>
<listitem>
<para>Specifies the query that is performed. The queries that can be
set here are defined in the database configuration file (either
</listitem>
</varlistentry>
<varlistentry>
<term><literal>"property"</literal></term>
<listitem>
<para>Defines the object property against which the range query is
performed. In the preceding example, the query is run against all
</listitem>
</varlistentry>
<varlistentry>
<term><literal>"condition"</literal> (optional)</term>
<listitem>
<para>Indicates the conditions that must be matched for the defined
property.</para>
<para>In the previous example, the scanner scans for users for whom the
current timestamp at the time the script is executed.</para>
<para>You can use these fields to define any condition. For example, if
you wanted to limit the scanned objects to a specified location, say,
London, you could formulate a query to compare against object locations
and then set the condition to be:</para>
<programlisting language="javascript">
"condition" : {
"location" : "London"
},</programlisting>
<para>For time-based conditions, the <literal>"condition"</literal>
in relation to the current time, using the <literal>+</literal> or
<literal>-</literal> operator, and a duration modifier. For example:
(current time plus one day). You must include space characters around the
operator (<literal>+</literal> or <literal>-</literal>). The duration
modifier supports the following unit specifiers:</para>
<simplelist>
<member><literal>s</literal> - second</member>
<member><literal>m</literal> - minute</member>
<member><literal>h</literal> - hour</member>
<member><literal>d</literal> - day</member>
<member><literal>M</literal> - month</member>
<member><literal>y</literal> - year</member>
</simplelist>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>"taskState"</literal></term>
<listitem>
<para>Indicates the fields that are used to track the status of the
task.</para>
<simplelist>
<member><literal>"started"</literal> specifies the field that stores
the timestamp for when the task begins.</member>
<member><literal>"completed”</literal> specifies the field that stores
the timestamp for when the task completes its operation.</member>
</simplelist>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>"recovery"</literal> (optional)</term>
<listitem>
<para>Specifies a configurable timeout, after which the task scanner
process ends. In a scenario with clustered OpenIDM instances, there
might be more than one task scanner running at a time. A task
cannot be executed by two task scanners at the same time. When one
task scanner "claims" a task, it indicates that the task has been
started. That task is then unavailable to be claimed by another task
scanner and remains unavailable until the end of the task is indicated.
In the event that the first task scanner does not complete the task by
the specified timeout, for whatever reason, a second task scanner can
pick up the task.</para>
</listitem>
</varlistentry>
</variablelist>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>"task"</literal></term>
<listitem><para>Provides details of the task that is performed. Usually,
the task is invoked by a script, whose details are defined in the
<literal>"script"</literal> property:</para>
<simplelist>
<member><literal>"type"</literal> - the type of script. Currently, only
JavaScript is supported.</member>
<member><literal>"file"</literal> - the path to the script file. The script
file takes at least two objects (in addition to the default objects that
are provided to all OpenIDM scripts): <literal>"input"</literal> which is
the individual object that is retrieved from the query (in the example,
this is the individual user object) and <literal>"objectID"</literal>
which is a string that contains the full identifier of the object. The
objectID is useful for performing updates with the script as it allows you
to target the object directly, for example:
directory. The sample script marks all user objects that match the
specified conditions as "inactive". You can use this sample script to
trigger a specific workflow, or any other task associated with the sunset
process. For more information about using scripts in OpenIDM, see the
<link xlink:href="integrators-guide#appendix-scripting"
xlink:role="http://docbook.org/xlink/role/olink">
<citetitle>Scripting Reference</citetitle></link>.</member>
</simplelist>
</listitem>
</varlistentry>
</variablelist>
</section>
<section xml:id="task-scanner-rest">
<title>Managing Scanning Tasks Over REST</title>
<para>You can trigger, cancel, and monitor scanning tasks over the REST
interface, using the REST endpoint
<section xml:id="triggering-task-scanner">
<title>Triggering a Scanning Task</title>
<para>The following REST command executes a task named "taskscan_sunrise".
The task itself is defined in a file named
<screen width="91"><?dbfo pgwide="1"?>$ curl
--header "X-OpenIDM-Username: openidm-admin"
--header "X-OpenIDM-Password: openidm-admin"
--request POST
</screen>
<para>By default, a scanning task ID is returned immediately when the task
is initiated. Clients can make subsequent calls to the task scanner service,
using this task ID to query its state and to call operations on it.</para>
<para>For example, the scanning task initiated previously would return
something similar to the following, as soon as it was initiated:</para>
<screen>{"_id":"edfaf59c-aad1-442a-adf6-3620b24f8385"}</screen>
<para>To have the scanning task complete before the ID is returned, set the
<literal>waitForCompletion</literal> property to <literal>true</literal>
You can also set the property directly over the REST interface when the task is
initiated. For example:</para>
<screen width="100"><?dbfo pgwide="1"?>$ curl
--header "X-OpenIDM-Username: openidm-admin"
--header "X-OpenIDM-Password: openidm-admin"
--request POST
</screen>
</section>
<section xml:id="canceling-task-scanner">
<title>Canceling a Scanning Task</title>
<para>You can cancel a scanning task by sending a REST call with the
<literal>cancel</literal> action, specifying the task ID. For example, the
following call cancels the scanning task initiated in the previous section.
</para>
<screen width="91"><?dbfo pgwide="1"?>$curl
--header "X-OpenIDM-Username: openidm-admin"
--header "X-OpenIDM-Password: openidm-admin"
--request POST
</screen>
<para>The output for a scanning task cancelation request is similar to the
following, but on a single line:</para>
<screen width="91">
{"_id":"edfaf59c-aad1-442a-adf6-3620b24f8385",
"action":"cancel",
"status":"SUCCESS"}
</screen>
</section>
<section xml:id="listing-task-scanner">
<title>Listing Scanning Tasks</title>
<para>You can display a list of scanning tasks that have completed, and
those that are in progress, by running a RESTful GET on
example displays all scanning tasks.</para>
<screen>$curl
--header "X-OpenIDM-Username: openidm-admin"
--header "X-OpenIDM-Password: openidm-admin"
--request GET
</screen>
<para>The output of such a request is similar to the following, with one
item for each scanning task. The output appears on a single line, but
has been indented here, for legibility.</para>
<screen width="91">{"tasks": [
{
"_id": "edfaf59c-aad1-442a-adf6-3620b24f8385",
"progress": {
"state": "COMPLETED",
"processed": 2400,
"total": 2400,
"successes": 2400,
"failures": 0
},
"started": 1352455546149,
"ended": 1352455546182
}
]
}
</screen>
<variablelist>
<para>Each scanning task has the following properties:</para>
<varlistentry>
<term><literal>_id</literal></term>
<listitem>
<para>The ID of the scanning task.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>progress</literal></term>
<listitem>
<para>The progress of the scanning task, summarised in the following
fields:</para>
<simplelist>
<member><literal>state</literal> - the overall state of the task,
<literal>INITIALIZED</literal>, <literal>ACTIVE</literal>, <literal>
COMPLETED</literal>, <literal>CANCELLED</literal>, or <literal>
ERROR</literal>
</member>
<member><literal>processed</literal> - the number of processed records
</member>
<member><literal>total</literal> - the total number of records</member>
<member><literal>successes</literal> - the number of records processed
successfully</member>
<member><literal>failures</literal> - the number of records not able
to be processed</member>
</simplelist>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>started</literal></term>
<listitem>
<para>The time at which the scanning task started, .</para>
</listitem>
</varlistentry> <varlistentry>
<term><literal>ended</literal></term>
<listitem>
<para>The time at which the scanning task ended.</para>
</listitem>
</varlistentry>
</variablelist>
<para>The number of processed tasks whose details are retained is governed
last one hundred completed tasks are retained.</para>
</section>
</section>
</section>
</chapter>