Lifecycle Events

If a task runner has methods of this name, they will be executed automatically.

  • preTask - Before any target in the task

  • postTask - After any target in the task

  • aroundTask - Wraps execution of any target in the task

  • pre<targetName> - Before a specific target (Ex: preRun)

  • post<targetName> - After a specific target (Ex: postRun)

  • around<targetName> - Wraps execution of a specific target (Ex: aroundRun)

  • onComplete - Fires regardless of exit status

  • onSuccess - Fires when task runs without failing exit code or exception

  • onFail - Fires if exit code is failing after the action is done (always fires along with onError, but does not receive an exception object). Use this to respond generally to failures of the job.

  • onError - fires only if an unhandled exception is thrown and receives exception object. Use this to respond to errors in the task. Does not fire for interrupted exceptions

  • onCancel - Fires when the task is interrupted with Ctrl-C

Every event receives the following data:

  • target - The name of the target executing

  • taskArgs - A struct containing the arguments for the target method

The onError event receives this additional data:

  • exception - The cfcatch object

The aroundTask and around<target> events receive the this additional data:

  • invokeUDF - A UDF to invoke to call the actual target method

A simple “around” event looks like this:

function aroundTask() {
return invokeUDF();
}

A more complex one, like this:

function aroundTask( string target, struct taskArgs, any invokeUDF ) {
print.line( 'aroundTask before #target#' );
local.result = invokeUDF();
print.line( 'aroundTask after #target#' );
if( !isNull( local.result ) ) {
return local.result;
}
}

It is important to return any value received from the invokeUDF() method (may return null) in case the original target returns an exit code. Otherwise, a failing exit code returned by the target will be ignored!

If you wish to modify the incoming arguments to the target, you may modify the taskArgs struct, which is passed by reference. It is not necessary to pass anything into the invokeUDF() method call.

function aroundTask( string target, struct taskArgs, any invokeUDF ) {
// Override incoming parameter
taskArgs.foo='bar';
return invokeUDF();
}

Control when lifecycle method fire with these this scoped variables in the task CFC. These are all comma-delimited lists. When empty, they are ignored. When at least one target name is specified in “only”, then ONLY those targets will have the corresponding event fire. Any targets listed in the “except” settings, will not fire. These settings apply to the primary target being executed as well as any 'depends” targets.

this.preTask_only='';
this.preTask_except='';
this.postTask_only='';
this.postTask_except='';
this.aroundTask_only='';
this.aroundTask_except='';
this.onComplete_only='';
this.onComplete_except='';
this.onSuccess_only='';
this.onSuccess_except='';
this.onFail_only='';
this.onFail_except='';
this.onError_only='';
this.onError_except='';
this.onCancel_only='';
this.onCancel_except='';

When one target depends on other targets, it makes sense for pre and post events to fire, but it doesn’t make sense for onComplete, onFail, onSuccess, onError, or onCancel to fire for each one since those are “final” events. As such, the following will only fire for the top level target being executed. (Keep in mind, if a “depends” target fails, the error will bubble up to the top level.

  • onError

  • onSuccess

  • onFail

  • onComplete

  • onCancel

If an aroundTask and around<target> method are both specified, they will both execute with the task-level one (more generic) wrapped “around” the target level one (more specific).

To clarify the order of execution, here is the output from a successful task running a “run” target that has every possible method above defined.

aroundTask prior to invokeUDF()
preTask
aroundRun prior to invokeUDF()
preRun
Task execution here
postRun
aroundRun after invokeUDF()
postTask

ColdBox notes: this feature is modeled after the pre/post/around features of ColdBox event handlers where a Task is analogous to a handler and a target is analogous to an action. There are some differences in how CommandBox’s pre/post/around events were implemented.

  • ColdBox does not allow an aroundhandler and around<action> at the same time, but CommandBox does allow an aroundTask and around<target> at the same time.

  • ColdBox executes pre/post before and after the around events. CommandBox wraps the pre/post code with the around code. This means, for example, exceptions raised by a preTask or postTask method can be try/caught in the aroundTask method.

  • For around methods, ColdBox passes a direct reference to the original action UDF to invoke and all the original arguments must be passed along by argumentCollection. CommandBox passes a special invoker UDF to around methods which does not require any arguments as it internally calls the original target method with the necessary arguments. This reduces boilerplate. In both cases, the return value of the UDF needs to be dealt with appropriately.