[[Jakarta_Batch]]
= Jakarta Batch Subsystem

ifdef::env-github[]
:tip-caption: :bulb:
:note-caption: :information_source:
:important-caption: :heavy_exclamation_mark:
:caution-caption: :fire:
:warning-caption: :warning:
endif::[]

[abstract]

The batch subsystem is used to configure an environment for running
batch applications. http://wildfly.org[WildFly] uses
https://github.com/jberet/jsr352[JBeret] for its Jakarta Batch implementation.
Specific information about JBeret can be found in the
http://jberet.gitbooks.io/jberet-user-guide/content/[user guide]. The
resource path, in <<CLI_Recipes,CLI notation>>, for the subsystem
is `subsystem=batch-jberet`.

[[default-subsystem-configuration]]
== Default Subsystem Configuration

For up to date information about subsystem configuration options see the
link:wildscribe[WildFly model reference^].

[[security]]
== Security

A new `security-domain` attribute was added to the `batch-jberet`
subsystem to allow batch jobs to be executed under that security domain.
Jobs that are stopped as part of a `suspend` operation will be restarted
on execution of a `resume` with the original user that started job.

There was a
`org.wildfly.extension.batch.jberet.deployment.BatchPermission` added to
allow a security restraint to various batch functions. The following
functions can be controlled with this permission.

* start
* stop
* restart
* abandon
* read

The read function allows users to use the getter methods from the
`jakarta.batch.operations.JobOperator` or read the `batch-jberet`
deployment resource, for example
`/deployment=my.war/subsystem=batch-jberet:read-resource`.

[[job-repository]]
== Job Repository

The batch subsystem supports 2 types of job repository:

* in-memory job repository: all job execution data are kept in the memory
of WildFly instance. When the server shuts down, all job execution data
are lost. In a clustered environment, each WildFly server instance has its
own in-memory job repository, and it is not possible to share job execution
data between WildFly instances. This is the default job repository in
batch subsystem.

* jdbc job repository: all job execution data are saved in a relational
database accessed via jdbc. In a clustered environment, a jdbc job repository
can be used to share job execution data between WildFly instances.
For example, one may start a job execution in one instance, stop and restart
it from a different WildFly instance.

=== Handling Large Job Repositories

In some cases, when a job repository accumulates a large number of job
execution records (say hundreds of thousands), application deployment times may
be negatively impacted. This is relevant mainly to persistent job repository
implementations, like the jdbc job repository.

In order to avoid accumulating too high a number of job execution records, the
application can delete old executions via
`JobOperator.abandon(long executionId)`, or other means like pruning the
database tables can be employed.

If it's no possible to avoid storing large number of job execution records,
the job repositories can be configured to limit the number of job executions
that is returned by them by setting the `execution-records-limit` attribute.
If the attribute is set, WildFly will only load specified maximum number of
job executions from the backing storage mechanism.

[[deployment-descriptors]]
== Deployment Descriptors

There are no deployment descriptors for configuring a batch environment
defined by the https://www.jcp.org/en/jsr/detail?id=352[JSR-352
specification]. In http://wildfly.org[WildFly] you can use a
`jboss-all.xml` deployment descriptor to define aspects of the batch
environment for your deployment.

In the `jboss-all.xml` deployment descriptor you can define a named job
repository, a new job repository and/or a named thread pool. A named job
repository and named thread pool are resources defined on the batch
subsystem. Only a named thread pool is allowed to be defined in the
deployment descriptor.

.Example Named Job Repository and Thread Pool

[source,xml,options="nowrap"]
----
<jboss xmlns="urn:jboss:1.0">
    <batch xmlns="urn:jboss:domain:batch-jberet:2.0">
      <job-repository>
        <named name="batch-ds"/>
      </job-repository>
      <thread-pool name="deployment-thread-pool"/>
    </batch>
</jboss>
----

.Example new Job Repository

[source,xml,options="nowrap"]
----
<jboss xmlns="urn:jboss:1.0">
    <batch xmlns="urn:jboss:domain:batch-jberet:2.0">
        <job-repository>
            <jdbc data-source="batch-ds"/>
        </job-repository>
    </batch>
</jboss>
----

[[deployment-resources]]
== Deployment Resources

Some subsystems in http://wildfly.org[WildFly] register runtime
resources for deployments. The batch subsystem registers jobs and
executions. The jobs are registered using the job name, this is _not_
the job XML name. Executions are registered using the execution id.

.Batch application in a standalone server

[source,options="nowrap"]
----
[standalone@localhost:9990 /] /deployment=batch-jdbc-chunk.war/subsystem=batch-jberet:read-resource(recursive=true,include-runtime=true)
{
    "outcome" => "success",
    "result" => {"job" => {
        "reader-3" => {
            "instance-count" => 1,
            "running-executions" => 0,
            "execution" => {"1" => {
                "batch-status" => "COMPLETED",
                "create-time" => "2015-08-07T15:37:06.416-0700",
                "end-time" => "2015-08-07T15:37:06.519-0700",
                "exit-status" => "COMPLETED",
                "instance-id" => 1L,
                "last-updated-time" => "2015-08-07T15:37:06.519-0700",
                "start-time" => "2015-08-07T15:37:06.425-0700"
            }}
        },
        "reader-5" => {
            "instance-count" => 0,
            "running-executions" => 0,
            "execution" => undefined
        }
    }}
}
----

The batch subsystem resource on a deployment also has 3 operations to
interact with batch jobs on the selected deployment. There is a
`start-job`, `stop-job` and `restart-job` operation. The `execution`
resource also has a `stop-job` and `restart-job` operation.

.Example start-job

[source,options="nowrap"]
----
[standalone@localhost:9990 /] /deployment=batch-chunk.war/subsystem=batch-jberet:start-job(job-xml-name=simple, properties={writer.sleep=5000})
{
    "outcome" => "success",
    "result" => 1L
}
----

.Example stop-job

[source,options="nowrap"]
----
[standalone@localhost:9990 /] /deployment=batch-chunk.war/subsystem=batch-jberet:stop-job(execution-id=2)
----

.Example restart-job

[source,options="nowrap"]
----
[standalone@localhost:9990 /] /deployment=batch-chunk.war/subsystem=batch-jberet:restart-job(execution-id=2)
{
    "outcome" => "success",
    "result" => 3L
}
----

.Result of resource after the 3 executions

[source,options="nowrap"]
----
[standalone@localhost:9990 /] /deployment=batch-chunk.war/subsystem=batch-jberet:read-resource(recursive=true, include-runtime=true)
{
    "outcome" => "success",
    "result" => {"job" => {"chunkPartition" => {
        "instance-count" => 2,
        "running-executions" => 0,
        "execution" => {
            "1" => {
                "batch-status" => "COMPLETED",
                "create-time" => "2015-08-07T15:41:55.504-0700",
                "end-time" => "2015-08-07T15:42:15.513-0700",
                "exit-status" => "COMPLETED",
                "instance-id" => 1L,
                "last-updated-time" => "2015-08-07T15:42:15.513-0700",
                "start-time" => "2015-08-07T15:41:55.504-0700"
            },
            "2" => {
                "batch-status" => "STOPPED",
                "create-time" => "2015-08-07T15:44:39.879-0700",
                "end-time" => "2015-08-07T15:44:54.882-0700",
                "exit-status" => "STOPPED",
                "instance-id" => 2L,
                "last-updated-time" => "2015-08-07T15:44:54.882-0700",
                "start-time" => "2015-08-07T15:44:39.879-0700"
            },
            "3" => {
                "batch-status" => "COMPLETED",
                "create-time" => "2015-08-07T15:45:48.162-0700",
                "end-time" => "2015-08-07T15:45:53.165-0700",
                "exit-status" => "COMPLETED",
                "instance-id" => 2L,
                "last-updated-time" => "2015-08-07T15:45:53.165-0700",
                "start-time" => "2015-08-07T15:45:48.163-0700"
            }
        }
    }}}
}
----

Pro Tip

[TIP]

You can filter jobs by an attribute on the execution resource with the
`query` operation.

.View all stopped jobs

[source,options="nowrap"]
----
/deployment=batch-chunk.war/subsystem=batch-jberet/job=*/execution=*:query(where=["batch-status", "STOPPED"])
----

As with all operations you can see details about the operation using the
`:read-operation-description` operation.

Tab completion

[TIP]

Don't forget that CLI has tab completion which will complete operations
and attributes (arguments) on operations.

.Example start-job operation description

[source,options="nowrap"]
----
[standalone@localhost:9990 /] /deployment=batch-chunk.war/subsystem=batch-jberet:read-operation-description(name=start-job)
{
    "outcome" => "success",
    "result" => {
        "operation-name" => "start-job",
        "description" => "Starts a batch job.",
        "request-properties" => {
            "job-xml-name" => {
                "type" => STRING,
                "description" => "The name of the job XML file to use when starting the job.",
                "expressions-allowed" => false,
                "required" => true,
                "nillable" => false,
                "min-length" => 1L,
                "max-length" => 2147483647L
            },
            "properties" => {
                "type" => OBJECT,
                "description" => "Optional properties to use when starting the batch job.",
                "expressions-allowed" => false,
                "required" => false,
                "nillable" => true,
                "value-type" => STRING
            }
        },
        "reply-properties" => {"type" => LONG},
        "read-only" => false,
        "runtime-only" => true
    }
}
----
