Skip to content

Commit 4813da5

Browse files
committed
making sure virtual threads only run on java 21
1 parent 2edf708 commit 4813da5

3 files changed

Lines changed: 36 additions & 12 deletions

File tree

system/async/executors/Executor.cfc

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -36,22 +36,26 @@ component accessors="true" singleton {
3636
"ScheduledThreadPoolExecutor" : {
3737
"pool" : true,
3838
"taskMethods" : true,
39-
"isTerminating" : true
39+
"isTerminating" : true,
40+
"queue" : true
4041
},
4142
"ThreadPoolExecutor" : {
4243
"pool" : true,
4344
"taskMethods" : true,
44-
"isTerminating" : true
45+
"isTerminating" : true,
46+
"queue" : true
4547
},
4648
"ForkJoinPool" : {
4749
"pool" : false,
4850
"taskMethods" : false,
49-
"isTerminating" : true
51+
"isTerminating" : true,
52+
"queue" : false
5053
},
5154
"ThreadPerTaskExecutor" : {
5255
"pool" : false,
5356
"taskMethods" : false,
54-
"isTerminating" : false
57+
"isTerminating" : false,
58+
"queue" : false
5559
}
5660
};
5761

@@ -89,7 +93,7 @@ component accessors="true" singleton {
8993
* The result of this call is a ColdBox FutureTask from which you can monitor,
9094
* cancel, or get the result of the the executing task.
9195
*
92-
* @callable THe callable closure/lambda/cfc to execute
96+
* @callable The callable closure/lambda/cfc to execute
9397
* @method The default method to execute if the runnable is a CFC, defaults to `run()`
9498
*
9599
* @return A ColdBox Future Task object
@@ -173,9 +177,9 @@ component accessors="true" singleton {
173177

174178
/**
175179
* Shuts down the executor in two phases, first by calling the shutdown() and rejecting all incoming tasks.
176-
* Second, calling shutdownNow() aggresively if tasks did not shutdown on time to cancel any lingering tasks.
180+
* Second, calling shutdownNow() aggressively if tasks did not shutdown on time to cancel any lingering tasks.
177181
*
178-
* @timeout The timeout in seconds to wait for the shutdown. By deafult we use the default on the property shutdownTimeout (30s)
182+
* @timeout The timeout in seconds to wait for the shutdown. By default we use the default on the property shutdownTimeout (30s)
179183
*/
180184
Executor function shutdownAndAwaitTermination( numeric timeout = variables.shutdownTimeout ){
181185
var sTime = getTickCount();
@@ -242,9 +246,14 @@ component accessors="true" singleton {
242246

243247
/**
244248
* Returns the task queue used by this executor.
249+
* If the executor has no queue, an empty LinkedBlockingQueue is returned.
250+
*
251+
* @return A queue that holds the tasks submitted to this executor.
245252
*/
246253
any function getQueue(){
247-
return variables.native.getQueue();
254+
return hasFeature( "queue" )
255+
? variables.native.getQueue()
256+
: createObject( "java", "java.util.concurrent.LinkedBlockingQueue" ).init();
248257
}
249258

250259
/**
@@ -315,12 +324,13 @@ component accessors="true" singleton {
315324
"isTerminated" : isTerminated(),
316325
"isTerminating" : isTerminating(),
317326
"isShutdown" : isShutdown(),
318-
"type" : variables.native.getClass().getName()
327+
"type" : variables.native.getClass().getName(),
328+
"queue": getQueue().toString()
319329
};
320330
}
321331

322332
/**
323-
* Utility to send to output to the output stream
333+
* Utility to send output to the output stream
324334
*
325335
* @var Variable/Message to send
326336
*/

tests/specs/async/ExecutorServicesSpec.cfc

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
*/
44
component extends="BaseAsyncSpec" {
55

6+
variables.javaMajorVersion = createObject( "java", "java.lang.System" ).getProperty( "java.version" ).listFirst( "." )
7+
68
function run( testResults, testBox ){
79
// all your suites go here.
810
describe( "ColdBox Async Executor Services", function(){
@@ -15,55 +17,64 @@ component extends="BaseAsyncSpec" {
1517
var executor = asyncManager.newExecutor( "unitTest" );
1618
expect( executor.getName() ).toBe( "unitTest" );
1719
expect( executor.getCorePoolSize() ).toBe( 20 );
20+
debug( executor.getStats() );
1821
expect( executor.getStats() ).toBeStruct();
1922
} );
2023
it( "can create the default fixed executor with custom threads", function(){
2124
var executor = asyncManager.newExecutor( name: "unitTest", threads: 100 );
2225
expect( executor.getName() ).toBe( "unitTest" );
2326
expect( executor.getCorePoolSize() ).toBe( 100 );
27+
debug( executor.getStats() );
2428
expect( executor.getStats() ).toBeStruct();
2529
} );
2630
it( "can create the a single executor", function(){
2731
var executor = asyncManager.newExecutor( name: "unitTest", type: "single" );
2832
expect( executor.getName() ).toBe( "unitTest" );
2933
expect( executor.getCorePoolSize() ).toBe( 1 );
34+
debug( executor.getStats() );
3035
expect( executor.getStats() ).toBeStruct();
3136
} );
3237
it( "can create the a cached executor", function(){
3338
var executor = asyncManager.newExecutor( name: "unitTest", type: "cached" );
3439
expect( executor.getName() ).toBe( "unitTest" );
3540
expect( executor.getPoolSize() ).toBe( 0 );
41+
debug( executor.getStats() );
3642
expect( executor.getStats() ).toBeStruct();
3743
} );
3844
it( "can create a fork_join executor", function(){
3945
var executor = asyncManager.newExecutor( name: "fork_join", type: "fork_join" );
4046
expect( executor.getName() ).toBe( "fork_join" );
4147
expect( executor.getPoolSize() ).toBe( 0 );
48+
debug( executor.getStats() );
4249
expect( executor.getStats() ).toBeStruct();
4350
} );
4451
it( "can create a work_stealing executor", function(){
4552
var executor = asyncManager.newExecutor( name: "work_stealing", type: "work_stealing" );
4653
expect( executor.getName() ).toBe( "work_stealing" );
4754
expect( executor.getPoolSize() ).toBe( 0 );
55+
debug( executor.getStats() );
4856
expect( executor.getStats() ).toBeStruct();
4957
} );
5058
it( "can create a scheduled executor", function(){
5159
var executor = asyncManager.newExecutor( name: "unitTest", type: "scheduled" );
5260
expect( executor.getName() ).toBe( "unitTest" );
5361
expect( executor.getCorePoolSize() ).toBe( 20 );
5462
expect( executor.getNative().toString() ).toInclude( "ScheduledThreadPoolExecutor" );
63+
debug( executor.getStats() );
5564
expect( executor.getStats() ).toBeStruct();
5665
} );
5766
// Skip on Adobe as their dumb reflection does not support virtual threads
5867
it(
5968
title: "can create a virtual thread executor",
6069
skip : (
61-
server.keyExists( "coldfusion" ) && server.coldfusion.productName.findNoCase( "ColdFusion" )
70+
( server.keyExists( "coldfusion" ) && server.coldfusion.productName.findNoCase( "ColdFusion" ) ) ||
71+
( variables.javaMajorVersion < 21 )
6272
),
6373
body: function(){
6474
var executor = asyncManager.newExecutor( name: "virtual", type: "virtual" );
6575
expect( executor.getName() ).toBe( "virtual" );
6676
expect( executor.getPoolSize() ).toBe( 0 );
77+
debug( executor.getStats() );
6778
expect( executor.getStats() ).toBeStruct();
6879
}
6980
);

tests/specs/async/executors/ExecutorsSpec.cfc

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
*/
44
component extends="tests.specs.async.BaseAsyncSpec" {
55

6+
variables.javaMajorVersion = createObject( "java", "java.lang.System" ).getProperty( "java.version" ).listFirst( "." )
7+
68
/*********************************** BDD SUITES ***********************************/
79

810
function run( testResults, testBox ){
@@ -45,7 +47,8 @@ component extends="tests.specs.async.BaseAsyncSpec" {
4547
it(
4648
title: "can create a virtual thread executor",
4749
skip : (
48-
server.keyExists( "coldfusion" ) && server.coldfusion.productName.findNoCase( "ColdFusion" )
50+
( server.keyExists( "coldfusion" ) && server.coldfusion.productName.findNoCase( "ColdFusion" ) ) ||
51+
( variables.javaMajorVersion < 21 )
4952
),
5053
body: () => {
5154
var executor = executors.newVirtualThreadExecutor();

0 commit comments

Comments
 (0)