diff --git a/build.gradle b/build.gradle
index b5b734bb5..71d6bf6c2 100644
--- a/build.gradle
+++ b/build.gradle
@@ -94,6 +94,7 @@ dependencies {
implementation 'com.coveo:spillway:3.0.0'
// monitoring
+ implementation 'io.micronaut.micrometer:micronaut-micrometer-core'
implementation 'io.micronaut.micrometer:micronaut-micrometer-registry-prometheus'
// Also required to enable endpoint
implementation 'io.micronaut:micronaut-management'
@@ -157,7 +158,7 @@ jib {
run{
def envs = findProperty('micronautEnvs')
- def args = ["-Dmicronaut.environments=$envs","-Djdk.tracePinnedThreads=short"]
+ def args = ["-Dmicronaut.environments=$envs","-Djdk.tracePinnedThreads=short", "--add-opens","java.base/java.lang=ALL-UNNAMED"]
if( environment['JVM_OPTS'] ) args.add(environment['JVM_OPTS'])
jvmArgs args
systemProperties 'DOCKER_USER': project.findProperty('DOCKER_USER') ?: environment['DOCKER_USER'],
diff --git a/gradle.properties b/gradle.properties
index 9c2c3bcbb..a89e1b2a7 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -17,4 +17,4 @@
#
micronautVersion=4.7.1
-micronautEnvs=dev,h2,mail,aws-ses
+micronautEnvs=dev,h2,mail,aws-ses,prometheus
diff --git a/src/main/groovy/io/seqera/wave/metrics/ExecutorsMetricsBinder.groovy b/src/main/groovy/io/seqera/wave/metrics/ExecutorsMetricsBinder.groovy
new file mode 100644
index 000000000..746c328ec
--- /dev/null
+++ b/src/main/groovy/io/seqera/wave/metrics/ExecutorsMetricsBinder.groovy
@@ -0,0 +1,82 @@
+/*
+ * Wave, containers provisioning service
+ * Copyright (c) 2023-2024, Seqera Labs
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package io.seqera.wave.metrics
+
+import java.lang.reflect.Field
+import java.util.concurrent.ForkJoinPool
+
+import groovy.transform.CompileStatic
+import groovy.util.logging.Slf4j
+import io.micrometer.core.instrument.MeterRegistry
+import io.micronaut.context.annotation.Context
+import jakarta.annotation.PostConstruct
+import jakarta.inject.Inject
+/**
+ *
+ * @author Paolo Di Tommaso
+ */
+@Slf4j
+@Context
+@CompileStatic
+class ExecutorsMetricsBinder {
+
+ @Inject
+ private MeterRegistry registry
+
+ @PostConstruct
+ void register() {
+ log.info "+ Registering executor metrics binder"
+ registerCommonPoolMetrics(registry)
+ registerVirtualThreadPoolMetrics(registry)
+ }
+
+ void registerCommonPoolMetrics(MeterRegistry meterRegistry) {
+ ForkJoinPool commonPool = ForkJoinPool.commonPool();
+
+ meterRegistry.gauge("common.pool.size", commonPool, ForkJoinPool::getPoolSize);
+ meterRegistry.gauge("common.active.thread.count", commonPool, ForkJoinPool::getActiveThreadCount);
+ meterRegistry.gauge("common.queued.submissions", commonPool, ForkJoinPool::getQueuedSubmissionCount);
+ meterRegistry.gauge("common.queued.tasks", commonPool, ForkJoinPool::getQueuedTaskCount);
+ meterRegistry.gauge("common.parallelism", commonPool, ForkJoinPool::getParallelism);
+ meterRegistry.gauge("common.steal.count", commonPool, ForkJoinPool::getStealCount);
+ }
+
+ void registerVirtualThreadPoolMetrics(MeterRegistry meterRegistry) {
+ try {
+ // Create a virtual thread executor
+ Class> VirtualThread = Class.forName("java.lang.VirtualThread");
+
+ // Use reflection to get the internal ForkJoinPool
+ Field poolField = VirtualThread.getDeclaredField("DEFAULT_SCHEDULER");
+ poolField.setAccessible(true);
+ ForkJoinPool virtualThreadPool = (ForkJoinPool) poolField.get(null);
+
+ // Register metrics for the virtual thread pool
+ meterRegistry.gauge("virtual.pool.size", virtualThreadPool, ForkJoinPool::getPoolSize);
+ meterRegistry.gauge("virtual.active.thread.count", virtualThreadPool, ForkJoinPool::getActiveThreadCount);
+ meterRegistry.gauge("virtual.queued.submissions", virtualThreadPool, ForkJoinPool::getQueuedSubmissionCount);
+ meterRegistry.gauge("virtual.queued.tasks", virtualThreadPool, ForkJoinPool::getQueuedTaskCount);
+ meterRegistry.gauge("virtual.parallelism", virtualThreadPool, ForkJoinPool::getParallelism);
+ meterRegistry.gauge("virtual.steal.count", virtualThreadPool, ForkJoinPool::getStealCount);
+ }
+ catch (Exception e) {
+ log.error "Unable to registry carrier threads pool metrics", e
+ }
+ }
+}