agentsclimarketplace

Async programming

Skill ColdBox/skills/coldbox/async-programming

Collection of skills for the ColdBox Platform and Claude Plugin

Install
npx -y skills add ColdBox/skills --skill async-programming

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

2 things to look at

  • no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
  • 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

Use this skill when building async pipelines, working with ColdBox Futures, running parallel computations with all()/allApply()/anyOf(), registering and managing thread-pool executors, or accessing the AsyncManager via the async() helper.

SKILL.md

6.9 KB, as published. Nobody here has run it

Async Programming (Futures & Executors)

When to Use This Skill

Use this skill when you need non-blocking operations, parallel workloads, async pipelines, or custom thread-pool management in ColdBox or any standalone Ortus library (WireBox, CacheBox, LogBox).

Language Mode Reference

Examples use BoxLang (.bx) syntax by default. Adapt for your target language:

ConceptBoxLang (.bx)CFML (.cfc)
Class declarationclass [extends="..."] {component [extends="..."] {
Arrow lambda( arg ) => expression( arg ) => expression
Closurefunction() { ... }function() { ... }

Core Concepts

  • AsyncManager — Central manager accessed via async() helper or WireBox injection @inject "asyncManager@coldbox"
  • ColdBox Future — Backed by Java CompletableFuture; created via newFuture() / newCompletedFuture()
  • Executors — Thread pools (fixed, cached, single, scheduled) registered in AsyncManager
  • Parallel methodsall(), allApply(), anyOf() for concurrent workloads
  • Available in any ColdBox/WireBox/CacheBox/LogBox application (not ColdBox-only)

Accessing the AsyncManager

// In a handler or interceptor — shortcut helper
var future = async().newFuture( () => someService.heavyWork() )

// Via injection
@inject("asyncManager@coldbox")
property name="asyncManager";

// In a non-ColdBox app
application.asyncManager = new coldbox.system.async.AsyncManager()

Creating Futures

// Constructor shortcut
var f = async().newFuture( () => userService.findAll() )

// run() method — also supports CFC + method name
var f = async().newFuture().run( () => userService.findAll() )
var f = async().newFuture().run( supplier: userService, method: "findAll" )

// Already-completed future (seed a value)
var f = async().newCompletedFuture( 42 )

// Complete an in-progress future with a fallback
var f = async().newFuture( () => fetch() ).complete( fallbackValue )

loadAppContext — pass loadAppContext: false when your task doesn't need CFML mappings/settings; reduces overhead and avoids context conflicts.

Building Pipelines

// Chain transformations with then()
var result = async()
    .newFuture( () => orderService.getOrders() )
    .then( ( orders ) => orders.filter( ( o ) => o.isPending() ) )
    .then( ( pending ) => pending.map( ( o ) => o.getMemento() ) )
    .get()  // blocking wait for final result

// Combine two futures
var combined = async()
    .newFuture( () => userService.getUser( userId ) )
    .thenCombine(
        async().newFuture( () => orderService.getOrders( userId ) ),
        ( user, orders ) => { user: user, orders: orders }
    )
    .get()

// Handle errors in pipeline
var safe = async()
    .newFuture( () => riskyService.fetch() )
    .exceptionally( ( ex ) => defaultValue )
    .get()

// Timeout an individual future
var result = async()
    .newFuture( () => slowService.compute() )
    .get( 5000, "milliseconds" )  // throws TimeoutException on expiry

Parallel Computations

all() — Wait for ALL results

// Pass closures or existing futures
var results = async()
    .newFuture()
    .all(
        () => hyper.post( "/service-a" ),
        () => hyper.post( "/service-b" ),
        () => hyper.post( "/service-c" )
    )
    .get()  // returns array of results in order

// With timeout across all
var results = async()
    .newFuture()
    .withTimeout( 10, "seconds" )
    .all( f1, f2, f3 )
    .get()

allApply() — Parallel map over a collection

// Array input — process each element in parallel
var mementos = async().allApply(
    orderService.findAll(),
    ( order ) => order.getMemento()
)

// Struct input — result object has key + value
var processed = async().allApply(
    configMap,
    ( item ) => item.key & "=" & item.value.toString()
)

// Custom executor for big workloads
var results = async().allApply(
    hugeList,
    ( item ) => processItem( item ),
    async().$executors.newFixedThreadPool( 50 )
)

anyOf() — Return the FASTEST result

// Race multiple futures — first to complete wins
var fastestDns = async()
    .newFuture()
    .anyOf(
        () => dns1.resolve( "example.com" ),
        () => dns2.resolve( "example.com" )
    )
    .get()

Executors

Executor Types

TypeDefault ThreadsBest For
fixed20Worker pools, multiple parallel tasks
cachedunbounded (60s TTL)Variable load, bursty workloads
single1Sequential FIFO ordering
scheduled20Periodic / one-off scheduled tasks

Registering & Using Executors

// Register a named executor (singleton — reused on subsequent calls)
var pool = async().newExecutor( "myWorkers", "fixed", 10 )

// Shortcuts
var scheduled = async().newScheduledExecutor( "heartbeat", 5 )
var singleQ   = async().newSingleExecutor( "auditQueue" )
var elastic   = async().newCachedExecutor( "httpPool" )

// Use executor for a future
var f = async().newFuture( () => work(), pool )

// Executor management
async().hasExecutor( "myWorkers" )      // boolean
async().getExecutorNames()              // array
async().shutdownExecutor( "myWorkers" ) // graceful
async().deleteExecutor( "myWorkers" )   // shutdown + remove
async().shutdownAllExecutors()

// Status snapshot
var stats = async().getExecutorStatusMap()

Handler Usage Patterns

class DataHandler extends coldbox.system.EventHandler {

    @inject("asyncManager@coldbox")
    property name="asyncManager";

    // Return a future directly — ColdBox renders when it resolves
    function index( event, rc, prc ) {
        return asyncManager.allApply(
            orderService.findAll(),
            ( order ) => order.getMemento()
        )
    }

    // Fire-and-forget background task
    function triggerReport( event, rc, prc ) {
        async().newFuture(
            () => reportService.buildReport( rc.reportId ),
            loadAppContext: false
        )
        event.renderData( data: { queued: true }, statusCode: 202 )
    }
}

Key Rules

  • Never call get() on the main request thread for long-running background work — it blocks the HTTP response. Use get() only when you genuinely need a synchronous result.
  • Use loadAppContext: false for pure computation tasks that don't need CFML mappings.
  • Prefer allApply() over manual looping for parallel collection processing.
  • Use withNoOverlaps() on scheduled tasks to prevent stacking (see scheduled-tasks skill).
  • Register long-lived executors once at startup, not per-request.

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.