BoxLang 🚀 A New JVM Dynamic Language Learn More...
Automatic job batching for ColdBox cbq. When a job exceeds a configurable item threshold, it automatically splits the workload into smaller parallel batches while preserving chained job execution.
box install cbq-autobatch
Inject the AutoBatch service and configure via props:
component extends="cbq.models.Jobs.AbstractJob" {
property name="autoBatch" inject="AutoBatch@cbq-autobatch";
function handle() {
var props = getProperties();
// Batch configuration - all in props
param props.autoBatch = true;
param props.batchSize = 20;
param props.batchItemsKey = "accounts"; // key containing struct to chunk
// ... resolve your items ...
props.accounts = loadAccounts();
// Check for auto-batching - just pass this and props
var result = autoBatch.evaluate( this, props );
if ( result.batched ) {
return result.result;
}
// Continue with single-job execution for items under threshold
processItems( props.accounts );
}
}
All configuration lives in props (with sensible defaults):
| Prop | Default | Description |
|---|---|---|
autoBatch
| false
| Enable auto-batching |
batchSize
| 10
| Items per batch |
batchQueue
| "default"
| Queue/connection for batch jobs |
batchItemsKey
| "items"
| Key in props containing struct to chunk |
batchMaxAttempts
| 2
| Retry attempts per batch job |
batchBackoff
| 60
| Seconds between retries |
batchJobTimeout
| 2400
| Individual job timeout in seconds (40 min) |
batchAllowFailures
| true
| Continue batch if some jobs fail |
batchThen
| - | Job/chain to run immediately after batch, before chained jobs |
batchFinally
| - | Job/chain to run after all chained jobs complete |
batchCarryover
| []
| Props to pass to children; if empty, passes ALL props |
| Prop | Value | Description |
|---|---|---|
bBatchChild
| true
| Flags this job as a batch child |
batchIndex
| 1-N
| 1-based index of this chunk |
batchTotal
| N
| Total number of chunks |
When a batch completes, jobs run in this order:
batchThen
- Runs immediately after batch completes.chain() on the original jobbatchFinally
- Runs after all chained jobs completeBatch completes → batchThen → chained jobs → batchFinally
Both batchThen and batchFinally accept
multiple formats:
props.batchThen = cbq.job( "reports.aggregate", { accountIDs : props.accountIDs } );
props.batchFinally = cbq.job( "notification", { message : "All done!" } );
Converted to a job automatically:
props.batchThen = {
job : "reports.aggregate",
properties : { accountIDs : props.accountIDs },
queue : "default",
timeout : 300
};
props.batchFinally = {
job : "reports.cleanup",
properties : { bForce : true }
};
Supported struct keys: job (or mapping),
properties, chain (or chained),
queue, connection, backoff,
timeout, maxAttempts
props.batchThen = [
cbq.job( "reports.aggregate", {} ),
cbq.job( "reports.validate", {} )
];
props.batchFinally = [
cbq.job( "reports.summary", {} ),
cbq.job( "notification", { message : "Reports complete" } )
];
autoBatch is
enabled and items exceed batchSize, batching kicks inbatchSize
bBatchChild = true to flag as a batch childbatchIndex and batchTotal for progress trackingautoBatch = false to prevent infinite recursionfinally() callbackbatchThen → chained
jobs → batchFinally
Configure defaults in your config/ColdBox.cfc:
moduleSettings = {
"cbq-autobatch" : {
defaultBatchSize : 10,
defaultBatchQueue : "default",
defaultMaxAttempts : 2,
defaultBackoff : 60,
defaultJobTimeout : 2400,
defaultAllowFailures : true
}
};
Batched jobs receive batchIndex and
batchTotal in their props:
function before() {
var props = getProperties();
if ( props.keyExists( "batchIndex" ) ) {
notify( "Processing batch #props.batchIndex# of #props.batchTotal#" );
}
}
Use bBatchChild to prevent after() from
running on child jobs (run only on parent/finally):
function after() {
var props = getProperties();
if ( !( props.bBatchChild ?: false ) ) {
super.after(); // Only run on parent or finally job
}
}
By default (empty batchCarryover), ALL props are passed
to child jobs, substituting the chunked items. Use
batchCarryover to explicitly limit which props are passed:
// Default: all props carried over (recommended for most cases)
var result = autoBatch.evaluate( this, props );
// Explicit: only pass specific props to children
props.batchCarryover = [ "sessionGUID", "parentLogID", "bDebug" ];
var result = autoBatch.evaluate( this, props );
MIT
$
box install cbq-autobatch