Skip to main content

Technical reference

The Job plugin provides a small set of base classes for building an asynchronous job execution pipeline: a Job to hold the work and its audit trail, a JobStatus enum to represent where that work stands, a JobRunner to hold configuration and do the work, and a JobExecutionTask to find pending jobs and run them on a schedule.

Dependencies

DependencyDescription
com.psddev:cms-dbProvides Content and the ToolUi annotations used to control how a job appears in the CMS tool.
com.psddev:dari-dbProvides Record, Query, and Modification, which Job and its supporting classes build on.
com.psddev:dari-utilProvides Task and RepeatingTask, which JobExecutionTask extends.
joda-timeUsed by JobExecutionTask to calculate its run schedule.

Installation

<!-- Requires Brightspot 4.5 or later. -->
<dependency>
<groupId>com.brightspot.job</groupId>
<artifactId>job</artifactId>
<version>1.2.0</version>
</dependency>

API reference

JobStatus

Interface that a job's status enum implements. Each enum value maps to a StatusProperty that tells the job execution system how to treat jobs in that status—whether they are still pending, should be retried, are polling for an external result, or have reached a terminal state.

MemberDescription
JobStatus#getProperty()Returns the StatusProperty for this status. Required. More than one status can share the same property.
JobStatus.StatusPropertyEnum of PRIORITY, PENDING, RETRY, POLLING, SUCCESS, PERMANENT_FAILURE, MAX_RETRIES.
JobStatus#isPending(), #isPriority(), #isRetriesAllowed(), #isPolling(), #isMaxRetriesExceeded(), #isPermanentFailure()Convenience checks against the corresponding StatusProperty.
JobStatus#isSuccessfulCompletion()True for SUCCESS statuses.
JobStatus#isUnsuccessfulCompletion()True for PERMANENT_FAILURE or MAX_RETRIES statuses.
JobStatus.values(Class)Static helper that returns all enum constants of a JobStatus class, regardless of property.
JobStatus.priorityStatuses(Class), #pendingStatuses(Class), #retryStatuses(Class), #pollingStatuses(Class), #maxRetriesStatuses(Class)Static helpers that return the enum constants of a JobStatus class matching the corresponding StatusProperty.
JobStatus.find(Class, String)Static helper that looks up a status by its enum name.

Job

Abstract Record representing a single queued unit of work, its current status, and its activity log. Extend this class for each distinct kind of job in your application.

Must implement:

MethodDescription
Job#getStatus()Returns the status of the most recent execution.
Job#setStatus(S)Sets the status of the most recent execution.

Provided:

MethodDescription
Job#getQueueDate()The date the job was queued. Set automatically on first save.
Job#getLastActivityDate()The date of the most recent status change.
Job#getCompletionStatus()SUCCESS or FAILURE once the job reaches a terminal state, null otherwise. Calculated automatically from #getStatus() on save.
Job#getLog()The ordered list of JobActivity entries recorded for this job.
Job#getAttempts()The number of execution attempts logged so far.
Job#getRetries(Class)The number of consecutive retry-eligible attempts since the last non-retry status.
Job#getSecondsInQueue()Seconds between the queue date and the last activity date.
Job#getRunner() / #setRunner(JobRunner)The JobRunner responsible for executing this job.
Job#logActivity(JobExecutionResult, Consumer<String>)Records the result of an execution, updates the job's status and last activity date, and invokes the supplied logger. Adds a new JobActivity entry to #getLog(), unless the result repeats the same polling status and message as the previous entry, in which case it increments a polling counter instead of adding a duplicate entry. Called by JobExecutionTask; not typically called directly from a JobRunner.
Job#afterLogActivity(JobExecutionResult, Consumer<String>)Override to run custom logic immediately after an activity is logged. No-op by default.
Job#calculateCompletionStatus()Derives SUCCESS, FAILURE, or null from the current status's isSuccessfulCompletion() / isUnsuccessfulCompletion().

JobRunner

Interface for the object that holds configuration for a group of jobs and does the actual work. JobRunner implementations are Records saved in the database so JobExecutionTask can find and enable or disable them without a deploy.

MethodDescription
JobRunner#execute(Job, Task)Does the job. parentTask is the JobExecutionTask supervising the execution. Return the resulting status and a message; the task applies the status to the job.
JobRunner#isEnabled()Return false to skip this runner entirely.
JobRunner#getTaskHostOrIpAddress()The hostname or IP address jobs for this runner are allowed to run on. Must resolve to the current host's IP address for the runner to execute; if null, or if it does not resolve to the current host, the runner is skipped on every execution cycle.
JobRunner#getMaxNumberOfRetries()Maximum retry attempts for statuses with a RETRY property.
JobRunner#getMinSecondsBetweenRetries()Minimum delay between retry attempts.
JobRunner#getMinSecondsBetweenPolls()Minimum delay between polling attempts.
JobRunner#getParallelLevel()Number of jobs to execute concurrently for this runner. Defaults to 1.
JobRunner#handleException(Job, Throwable)Return a JobExecutionResult if #execute throws.

JobExecutionResult

The status and message returned from JobRunner#execute(Job, Task) or #handleException(Job, Throwable). JobExecutionTask applies this result to the job by calling Job#logActivity(JobExecutionResult, Consumer).

ConstructorDescription
JobExecutionResult(S status, String message)Creates a result with the given status and message.
JobExecutionResult(S status, String message, Throwable exception)Creates a result with the given status, and appends the exception's stack trace to the message.

JobExecutionTask

Abstract RepeatingTask that queries for pending jobs and executes them using their configured JobRunners, in priority, pending, retry, then polling order.

Provided:

MethodDescription
JobExecutionTask#jobClass()The Job subclass to query for. Resolved automatically from the subclass's generic type parameter; override only if that parameter is not a concrete class.
JobExecutionTask#jobRunnerClass()The JobRunner subclass to query for. Resolved automatically the same way as #jobClass(). Can be an abstract class shared by multiple runner implementations, in which case all matching jobs run through the same task.
JobExecutionTask#statusClass()The JobStatus enum used to determine which statuses are pending, retryable, and so on. Resolved automatically the same way as #jobClass().

Configuration

Override the following methods on a JobExecutionTask subclass to change how often and how many jobs it processes:

MethodDefaultDescription
JobExecutionTask#getRunEverySeconds()3How often the task checks for jobs to run.
JobExecutionTask#getBatchSize()10Number of pending, retry, or polling jobs fetched per runner on each run.
JobExecutionTask#getPriorityBatchSize()10Number of priority jobs fetched per runner on each run.
JobExecutionTask#getEnabledRunnersCacheSeconds()15How long the list of enabled job runners is cached before being requeried.

Override JobRunner#getParallelLevel(), #getMaxNumberOfRetries(), #getMinSecondsBetweenRetries(), and #getMinSecondsBetweenPolls() to control concurrency and retry timing per runner, since JobRunner instances are database records that can be reconfigured without a deploy.

Task framework

The task framework (task-core and its companion modules) is a lower-level alternative to JobExecutionTask for scheduling repeating and cron-based work that runs outside the job queue—for example, work that has no job asset of its own, or that needs an owner other than a single shared execution loop, such as a global instance, a per-site instance, or another owning entity.

Dependencies

DependencyDescription
com.psddev:dari-utilProvides Task, which AbstractRepeatingTask extends.

Installation

<!-- Requires Brightspot 4.5 or later. -->
<dependency>
<groupId>com.brightspot.job</groupId>
<artifactId>task-core</artifactId>
<version>1.2.0</version>
</dependency>

Add the companion module for the scheduling style needed—cron-configuration, logging-task, import-task, or one of the global-, site-, or variable- prefixed repeating and repeating-cron task modules—the same way, using its own artifactId.

Dispatcher and Dispatchable

A Dispatcher creates and manages Dispatchables: units of work that can be submitted once, scheduled after a delay, or scheduled to repeat with a fixed delay or fixed rate. TaskDispatcher is the provided Dispatcher implementation, built on the original Brightspot RepeatingTask; avoid implementing a custom Dispatcher.

MemberDescription
Dispatchable#submit()Runs the Dispatchable immediately. No-op if it is already scheduled.
Dispatchable#schedule(double)Runs the Dispatchable once, after the given delay in seconds.
Dispatchable#scheduleWithFixedDelay(double, double)Runs the Dispatchable repeatedly, waiting the given periodic delay after each run finishes.
Dispatchable#scheduleWithFixedRate(double, double)Runs the Dispatchable repeatedly at the given periodic rate, regardless of how long each run takes.
Dispatchable#pause() / #resume()Requests that a running Dispatchable pause or resume.
Dispatchable#stop()Requests that a running Dispatchable stop.
Dispatchable#isRunning(), #isPauseRequested(), #isSafeToStop()Status checks used while managing the Dispatchable's lifecycle.
Dispatchable#getProgress(), #getProgressIndex(), #getProgressTotal()Progress reporting for a long-running Dispatchable.
Dispatchable#getLastException()The last Throwable thrown during execution.
DispatchableConfiguration#create()Creates a Dispatchable from this configuration. Requires the configuration class to have a public no-argument constructor.
DispatchableConfiguration#isEnabled()Whether the configured Dispatchable should be considered for execution.
DispatchableConfiguration#getTaskHost()The host the Dispatchable is allowed to run on. Falls back to the default task host configured on GlobalTaskSettings when not overridden.
DispatchableDescriptorIdentifies a Dispatchable by its owner ID (a CmsTool, Site, or other owning entity) and Dispatchable class.

RepeatingTask

RepeatingTask extends Dispatchable for work that reschedules itself after every run until it is stopped. It is unrelated to the original Brightspot RepeatingTask from dari-util.

MemberDescription
RepeatingTask#calculateNextRunTime(Instant, Instant)Calculates the next run time from the previous run time and the current time.
RepeatingTask#doRepeatingTask(Instant)Runs the task for the given run time.
RepeatingTask#getPreviousRunTime()An AtomicReference to the previous run time.
AbstractRepeatingTaskBase implementation, extending Brightspot's Task.
RepeatingTaskUtilsUtility methods for calculating run times and checking whether a RepeatingTask is allowed to run on the current task host.

A RepeatingTask is added to TaskDispatcher's registry automatically. Assign it to an executor via DispatchableExecutor.

Cron scheduling

cron-configuration adds CronConfiguration, a contract for evaluating run times from a cron expression, independent of the rest of the task framework.

MemberDescription
CronConfiguration#getCronExpression()The cron expression that determines the task's run time.
CronConfiguration#getLastRunTime()The last run time, used to evaluate the next run time.

repeating-cron-task combines RepeatingTask with CronConfiguration as RepeatingCronTask, calculating its next run time from the cron expression instead of a fixed interval.

Task ownership: global, site, and variable

RepeatingTask and RepeatingCronTask are further specialized by who owns and runs the task:

ModuleOwnerCron support
global-repeating-taskA single global instance (GlobalRepeatingTask)No
site-repeating-taskOne instance per Site (SiteRepeatingTask, keyed by getSiteId())No
variable-repeating-taskAny owning entity (VariableRepeatingTask)No
global-repeating-cron-taskA single global instance (GlobalRepeatingCronTask)Yes
site-repeating-cron-taskOne instance per Site (SiteRepeatingCronTask)Yes
variable-repeating-cron-taskAny owning entity (VariableRepeatingCronTask)Yes

Each module provides a matching *Configuration interface (for example, SiteRepeatingTaskConfiguration#get(Site)) that generates the task name and resolves the owning entity.

Logging and importing

logging-task adds LoggingTask, a contract for a repeating task to record a TaskLog—a start and end time, plus a TaskStatus—for its most recent run. FileBackedTaskLog, and its JsonFileBackedTaskLog and PlainTextFileBackedTaskLog extensions, persist the log contents to a StorageItem.

import-task builds on logging-task for tasks that import assets from an external source:

MemberDescription
ImportTask#getConfiguration()Returns the ImportTaskConfiguration describing which Importers to run.
ImportTaskConfiguration#getImporters()The set of Importers this task runs.
ImportTaskConfiguration#areImportersAvailable()Whether the importers are currently available to run.
Importer#doImport(T)Imports a single item and returns a ChangeLog describing what changed.
ImportTaskLog#getChangeLog()The ChangeLog recorded for a run of the ImportTask.

ChangeLog, Change, and Issue (under brightspot.task.importer.changelog) record what an import changed and any issues it encountered, for display in the task's log.

Subscribable jobs

subscribable-jobs extends Job with support for publishing a CMS notification whenever a job's status changes.

Installation

<!-- Requires Brightspot 4.5 or later. -->
<dependency>
<groupId>com.brightspot.job</groupId>
<artifactId>subscribable-jobs</artifactId>
<version>1.2.0</version>
</dependency>

API reference

MemberDescription
SubscribableJob#getPublisherClass()Returns the JobPublisher class to use for this job. Must implement.
SubscribableJob#getLogger()Returns the Logger used to report publishing failures. Must implement.
SubscribableJob#isEnabled()Whether notifications are enabled for this job. true by default.
JobPublisher<S, C>A Publisher that sends notifications for a JobSubscription of type S regarding a SubscribableJob of type C.
JobSubscription<J>A ToolSubscription for a SubscribableJob of type J. Extend it to add filter criteria—for example, which statuses to notify on—and override how the notification is rendered.

SubscribableJob publishes a notification after every Job#logActivity(JobExecutionResult, Consumer) call, immediately after Job#afterLogActivity(JobExecutionResult, Consumer) runs.

CMS Scripts

cms-scripts-core builds on the job execution framework to provide a CMS tool for running and auditing administrative scripts. See Working with CMS Scripts for the editorial workflow.

Dependencies

DependencyDescription
com.brightspot.job:jobProvides Job, JobRunner, and JobStatus, which the script job execution flow builds on.
com.brightspot.job:subscribable-jobsProvides SubscribableJob, which ScriptJob extends to support notifications.
com.brightspot.job:task-coreProvides RepeatingTaskUtils, used by AbstractAsyncProcessQueryScript (from cms-scripts-async).

Installation

<!-- Requires Brightspot 4.5 or later. -->
<dependency>
<groupId>com.brightspot.job</groupId>
<artifactId>cms-scripts-core</artifactId>
<version>1.2.0</version>
</dependency>

For a base script implementation that processes a Query result set asynchronously across multiple writer threads, also add:

<!-- Requires Brightspot 4.5 or later. -->
<dependency>
<groupId>com.brightspot.job</groupId>
<artifactId>cms-scripts-async</artifactId>
<version>1.2.0</version>
</dependency>

API reference

Script

The contract every script implementation must satisfy. A Script is a Recordable—its fields are rendered as the script's form in the Scripts area—and also the unit of execution logic.

MemberDescription
Script#execute(ScriptJob, Task)Runs the script's logic and returns a ScriptJobExecutionResult. Must implement.
Script#handleException(ScriptJob, Throwable)Handles an exception thrown by #execute. Returns PERMANENT_FAILURE with the stack trace by default.
Script#getScriptDisplayOrder()Where this script sorts on the Scripts page relative to other scripts. Negative values sort above the alphabetical group, positive values sort below it. Defaults to 0.
Script#getShortLabel()The script's label with the "Script" suffix removed.
Script.getAllInstances()Static helper that returns an instance of every concrete Script implementation found on the classpath.

ScriptJob

A SubscribableJob<ScriptJobStatus> that records a single script execution: which Script ran, the ToolUser who ran it, and its duration.

MemberDescription
ScriptJob#getScript() / #setScript(Script)The Script configuration this job runs.
ScriptJob#getUser()The ToolUser who queued the job.
ScriptJob#getDurationInMilliseconds() / #getDurationLabel()The execution duration, as a raw value or a formatted label (for example, 1h2m3s).
ScriptJob#isRunning()Whether the job is currently executing.
ScriptJob.queue(Script, ToolUser)Static helper that creates and immediately saves a pending ScriptJob for the given script and user.

ScriptJobStatus

The JobStatus enum for ScriptJob: PENDING, SUCCESS, DATABASE_EXCEPTION (retry), MAX_RETRIES, UNHANDLED_EXCEPTION (permanent failure), PERMANENT_FAILURE, INVALID_JOB (permanent failure), PAUSED and WAITING (polling), UNPAUSED (pending), and CANCELED (permanent failure).

ScriptJobRunner

The single JobRunner<ScriptJob, ScriptJobStatus> Singleton that executes every ScriptJob by delegating to its Script#execute(ScriptJob, Task). Its configuration—enabled, task host, retry, and poll settings—comes from ScriptJobTool.

ScriptJobTool

The Tool configuration for the Scripts area, edited from Sites & Settings > Legacy Settings > Brightspot Scripts.

MemberDescriptionDefault
ScriptJobTool#isEnabled()Whether script job execution is enabled.false
ScriptJobTool#getTaskHost()The host script jobs are allowed to run on. Falls back to GlobalTaskSettings#getDefaultTaskHost() when not set.
ScriptJobTool#getMaximumNumberOfRetries()Maximum retry attempts for a retryable script job status.20
ScriptJobTool#getMinimumNumberOfSecondsBetweenRetries()Minimum delay between retries.3
ScriptJobTool#getMinimumNumberOfSecondsBetweenPolls()Minimum delay between polling attempts.3

Notifications

ScriptJobPublisher and ScriptJobSubscription are the JobPublisher and JobSubscription for ScriptJob. ScriptJobSubscription filters on a set of ScriptJobState values (a simplified grouping of terminal ScriptJobStatus values) and a set of script types, and renders the notification as an HTML summary of the script, status, queue date, duration, and user.

Permissions

ScriptPermission is an AdditionalPermission that controls which scripts a ToolRole can access, backed by a ScriptPermissionOption: AllScriptsPermissionOption, NoneScriptsPermissionOption, OnlyScriptsPermissionOption (allow-list), or AllExceptScriptsPermissionOption (deny-list).

Batch scripts

Scripts can also be grouped into a BatchScriptsProfile and run together. BatchScriptsJob, BatchScriptsJobRunner, and the rest of the com.psddev.script.batch package mirror the single-script ScriptJob classes for a profile's scripts. A BatchScriptSchedule—created via BatchScriptSchedule.schedule(BatchScriptsProfile, ToolUser, Date)—queues a profile's BatchScriptsJob once a BatchScriptScheduleTask finds it due.

Was this page helpful?

This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.