Whatever message this page gives is out now! Go check it out!
<cfscript>
getAccountBalance = function(){
var balance = 120000;
return balance;
}
function payCreditCardBill(accountBalance){
var ccBill = 1890;
return accountBalance-ccBill;
}
payEMIs = function(accountBalance){
var mortgageEMI = 1000;
var carLeaseEMI = 750;
var healthInsuranceEMI = 250;
return accountBalance-(mortgageEMI+carLeaseEMI+healthInsuranceEMI);
}
miscellenousExpenses = function(accountBalance){
var shopping = 1500;
var clubExpense =1000;
var casinoExpense = 2000;
return accountBalance-(shopping+clubExpense+casinoExpense);
}
checkBalance = function(accountBalance){
while(accountBalance > 5000){
accountBalance = miscellenousExpenses(accountBalance);
}
if(accountBalance < 5000)
throw (message="Account balance below threshold!!!", type="info");
}
errorHandler = function(error){
if(error.message contains "Account balance below threshold!"){
return "You have reached your spending limit!";
}
}
future = runAsync(getAccountBalance).then(payCreditCardBill).then(payEMIs).
then(miscellenousExpenses).then(checkBalance).error(errorHandler);
writelog(future.get());
</cfscript><cfscript>
future = runAsync(function(){return "I am invoked from RunAsync directly!";});
</cfscript><cfscript>
p = runAsync(); // empty future
p.complete(10);
writelog(p.get()); // displays 10
</cfscript><cfscript>
// Login is always required.
adminObj = createObject("component","cfide.adminapi.administrator");
adminObj.login("admin");
runtimeObj=createObject("component","cfide.adminapi.runtime");
corePool=runtimeObj.getRuntimeProperty("corePoolSize");
writeOutput("core pool size is: " & corePool & "<br/>");
maxPool=runtimeObj.getRuntimeProperty("maxPoolSize");
writeOutput("max pool size is: " & maxPool & "<br/>");
keepAlive=runtimeObj.getruntimeProperty("keepAliveTime");
writeOutput("keep alive time is: " & keepAlive & "<br/>");
</cfscript>get() on a prior stage from inside a worker that was supposed to run the next step, tying up that thread until the dependency finished. Under load, the pool could run out of idle workers and throughput dropped even when CPUs had spare capacity.Future type with CompletableFuture. Stages can be wired with callbacks that return the thread to the pool instead of parking it on get(). You still use runAsync(), then(), and error() as before. You can add coordination helpers, timeouts, and explicit sync or async stage methods when you need finer control.get(). After Update 8, that handle participates in the same completion-stage model Java code uses with CompletableFuture.Future extends CompletableFuture<Object>. Any API that accepts a CompletableFuture can receive a CF Future. You can also call Java stage methods directly on the same object. The type relationship is one way: every CF Future is a CompletableFuture, but a CompletableFuture created in Java is not automatically a CF Future.CompletableFuture execution — for example, async supplier-style scheduling on the ColdFusion executor. Chaining via CF then() is implemented with non-blocking composition internally instead of blocking on the previous result inside the worker.runAsync plus then are less likely to pin many pool threads in a wait state. You still need to avoid calling get() inside small callbacks if those callbacks should stay non-blocking. Reserve get() for request boundaries, tests, or places where blocking is intentional.*Async methods when the follow-up may run for a long time, performs I/O, or should not occupy the completing thread. The executor runs the callback later. More hand-offs occur, so use async stages when the work justifies the extra scheduling cost.then() remains the fluent continuation many apps already use. It is implemented with non-blocking composition in this update. When you need Java-named operations — for example thenCombine with two futures — you can call them on the same object. Keep chaining style consistent so you do not lose CF-only methods mid-pipeline.asyncAllOf(array)then().asyncAnyOf(array)thenCombine / thenCombineAsyncget() pairing. The combiner receives both results when both succeed.applyToEitherAsync / acceptEitherAsyncrunAfterEitherAsyncorTimeout(timeoutMs)get(); if you call get() first on an unbounded stage, the caller waits without the timeout guard.completeOnTimeout(value, timeoutMs)thenApplyAsync(fn)thenComposeAsync(fn)thenCombineAsync(other, fn)thenApply, thenCompose, handle, whenComplete, and others — run on the completing thread and add less scheduling overhead when the follow-up is trivial.handle(fn) / handleAsync(fn)exceptionally(fn) / exceptionallyAsync(fn)exceptionallyCompose(fn) / exceptionallyComposeAsync(fn)whenComplete(fn) / whenCompleteAsync(fn)handle when the next stage must always produce a new value.userIdFuture = runAsync( function() { return 42; } );
profileFuture = userIdFuture.thenComposeAsync( function( id ) {
return runAsync( function() {
// load profile by id
return { id: id, name: "Example" };
} );
} );
writeOutput( serializeJSON( profileFuture.get() ) );
// Output: {"ID":42,"NAME":"Example"}runAsync( function() { return 10; } )
.thenApplyAsync( function( n ) { return n * 2; } )
.then( function( n ) { writeOutput( n ); } );f1 = runAsync( function() { return 1; } );
f2 = runAsync( function() { return 2; } );
allDone = asyncAllOf( [ f1, f2 ] );
allDone.then( function() {
total = f1.get() + f2.get();
writeOutput( total ); // 3
} );f1 = runAsync( function() { sleep( 300 ); return "slow"; } );
f2 = runAsync( function() { return "fast"; } );
first = asyncAnyOf( [ f1, f2 ] );
writeOutput( first.get() ); // fastslow = runAsync( function() { sleep( 5000 ); return "done"; } ).orTimeout( 3000 );
try {
writeOutput( slow.get() );
} catch ( any e ) {
writeOutput( "Timed out" );
}slow = runAsync( function() { sleep( 6000 ); return "too late"; } )
.completeOnTimeout( "DEFAULT", 5000 );
writeOutput( slow.get() ); // DEFAULTfuture1 = runAsync( function() { return "Hello"; } );
future2 = runAsync( function() { return "World"; } );
CompletableFutureClass = createObject( "java", "java.util.concurrent.CompletableFuture" );
combined = CompletableFutureClass.allOf( [ future1, future2 ] );
combined.get();
writeOutput( future1.get() & " " & future2.get() ); // Hello WorldCompletableFuture is expected and call Java stage methods on a CF Future. However, asyncAllOf() and asyncAnyOf() expect an array of CF Future values. A plain Java CompletableFuture can produce a type error because those helpers are typed to CF futures, not every Java completion stage.then() and Java thenApply() in one chain. Calling thenApply on a CF Future returns a CompletableFuture view that is not guaranteed to expose CF-only methods such as then(). Pick one style per pipeline segment. A safe pattern is to finish CF-specific chaining, then treat the remainder as Java-only, or copy the result into a new runAsync if you must return to CF helpers.runAsync() for CF-authored tasks. CompletableFuture.supplyAsync with a CF closure can fail when the runtime cannot create the required functional-interface proxy. If a call fails at runtime when passing CF closures where Java expects certain functional interfaces, move the body into runAsync and chain with CF-friendly methods instead.runAsync() so you hold real Future instances.asyncAllOf or asyncAnyOf when the arity is a list. Choose thenCombine when you have exactly two futures and a merge function.get() inside chained callbacks unless you accept blocking that callback.get() versus join() when you read Java docs; CF callers often use get() with try or catch.