Avoid direct access to executor to record worker pool metrics

Closes #22742
This commit is contained in:
Alexander Schwartz 2023-08-28 10:51:39 +02:00 committed by Alexander Schwartz
parent 798c6a5aaa
commit 8c5818a46e
3 changed files with 32 additions and 29 deletions

View file

@ -29,7 +29,6 @@ import io.quarkus.deployment.annotations.Produce;
import io.quarkus.deployment.annotations.Record; import io.quarkus.deployment.annotations.Record;
import io.quarkus.deployment.builditem.BootstrapConfigSetupCompleteBuildItem; import io.quarkus.deployment.builditem.BootstrapConfigSetupCompleteBuildItem;
import io.quarkus.deployment.builditem.CombinedIndexBuildItem; import io.quarkus.deployment.builditem.CombinedIndexBuildItem;
import io.quarkus.deployment.builditem.ExecutorBuildItem;
import io.quarkus.deployment.builditem.FeatureBuildItem; import io.quarkus.deployment.builditem.FeatureBuildItem;
import io.quarkus.deployment.builditem.GeneratedResourceBuildItem; import io.quarkus.deployment.builditem.GeneratedResourceBuildItem;
import io.quarkus.deployment.builditem.HotDeploymentWatchedFileBuildItem; import io.quarkus.deployment.builditem.HotDeploymentWatchedFileBuildItem;
@ -567,7 +566,7 @@ class KeycloakProcessor {
@Record(ExecutionTime.RUNTIME_INIT) @Record(ExecutionTime.RUNTIME_INIT)
@BuildStep @BuildStep
void initializeFilter(BuildProducer<FilterBuildItem> filters, KeycloakRecorder recorder, ExecutorBuildItem executor, NonApplicationRootPathBuildItem nonApplicationRootPathBuildItem) { void initializeFilter(BuildProducer<FilterBuildItem> filters, KeycloakRecorder recorder, NonApplicationRootPathBuildItem nonApplicationRootPathBuildItem) {
List<String> ignoredPaths = new ArrayList<>(); List<String> ignoredPaths = new ArrayList<>();
@ -583,7 +582,7 @@ class KeycloakProcessor {
.orElse(QUARKUS_DEFAULT_METRICS_PATH))); .orElse(QUARKUS_DEFAULT_METRICS_PATH)));
} }
filters.produce(new FilterBuildItem(recorder.createRequestFilter(ignoredPaths, executor.getExecutorProxy()),FilterBuildItem.AUTHORIZATION - 10)); filters.produce(new FilterBuildItem(recorder.createRequestFilter(ignoredPaths),FilterBuildItem.AUTHORIZATION - 10));
} }
@BuildStep @BuildStep

View file

@ -20,7 +20,6 @@ package org.keycloak.quarkus.runtime;
import java.lang.annotation.Annotation; import java.lang.annotation.Annotation;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.function.BiConsumer; import java.util.function.BiConsumer;
import java.util.function.Predicate; import java.util.function.Predicate;
@ -142,8 +141,8 @@ public class KeycloakRecorder {
}; };
} }
public QuarkusRequestFilter createRequestFilter(List<String> ignoredPaths, ExecutorService executor) { public QuarkusRequestFilter createRequestFilter(List<String> ignoredPaths) {
return new QuarkusRequestFilter(createIgnoredHttpPathsPredicate(ignoredPaths), executor); return new QuarkusRequestFilter(createIgnoredHttpPathsPredicate(ignoredPaths));
} }
private Predicate<RoutingContext> createIgnoredHttpPathsPredicate(List<String> ignoredPaths) { private Predicate<RoutingContext> createIgnoredHttpPathsPredicate(List<String> ignoredPaths) {

View file

@ -17,7 +17,6 @@
package org.keycloak.quarkus.runtime.integration.web; package org.keycloak.quarkus.runtime.integration.web;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.atomic.LongAdder; import java.util.concurrent.atomic.LongAdder;
import java.util.function.Predicate; import java.util.function.Predicate;
@ -53,17 +52,14 @@ public class QuarkusRequestFilter implements Handler<RoutingContext>, Transactio
private final Logger logger = Logger.getLogger(QuarkusRequestFilter.class); private final Logger logger = Logger.getLogger(QuarkusRequestFilter.class);
private final ExecutorService executor; private final Predicate<RoutingContext> contextFilter;
private Predicate<RoutingContext> contextFilter;
public QuarkusRequestFilter() { public QuarkusRequestFilter() {
this(null, null); this(null);
} }
public QuarkusRequestFilter(Predicate<RoutingContext> contextFilter, ExecutorService executor) { public QuarkusRequestFilter(Predicate<RoutingContext> contextFilter) {
this.contextFilter = contextFilter; this.contextFilter = contextFilter;
this.executor = executor;
} }
private final LongAdder rejectedRequests = new LongAdder(); private final LongAdder rejectedRequests = new LongAdder();
@ -78,7 +74,18 @@ public class QuarkusRequestFilter implements Handler<RoutingContext>, Transactio
// our code should always be run as blocking until we don't provide a better support for running non-blocking code // our code should always be run as blocking until we don't provide a better support for running non-blocking code
// in the event loop // in the event loop
try { try {
executor.execute(createBlockingHandler(context)); // When running in Quarkus dev mode, this will run on Vert.x default worker pool.
// When running in Quarkus production mode, this will run on the Quarkus executor pool.
// It should not call the Quarkus executor directly, as this prevents metrics for `worker_pool_*` to be collected.
// See https://github.com/quarkusio/quarkus/issues/34998 for a discussion.
context.vertx().executeBlocking(ctx -> {
try {
runBlockingCode(context);
ctx.complete();
} catch (Throwable ex) {
ctx.fail(ex);
}
}, false, null);
if (loadSheddingActive) { if (loadSheddingActive) {
synchronized (rejectedRequests) { synchronized (rejectedRequests) {
if (loadSheddingActive) { if (loadSheddingActive) {
@ -107,22 +114,20 @@ public class QuarkusRequestFilter implements Handler<RoutingContext>, Transactio
return contextFilter != null && contextFilter.test(context); return contextFilter != null && contextFilter.test(context);
} }
private Runnable createBlockingHandler(RoutingContext context) { private void runBlockingCode(RoutingContext context) {
return () -> { KeycloakSession session = configureContextualData(context);
KeycloakSession session = configureContextualData(context);
try { try {
context.next(); context.next();
} catch (Throwable cause) { } catch (Throwable cause) {
// re-throw so that the any exception is handled from parent // re-throw so that the any exception is handled from parent
throw new RuntimeException(cause); throw new RuntimeException(cause);
} finally { } finally {
// force closing the session if not already closed // force closing the session if not already closed
// under some circumstances resteasy might not be invoked like when no route is found for a particular path // under some circumstances resteasy might not be invoked like when no route is found for a particular path
// in this case context is set with status code 404, and we need to close the session // in this case context is set with status code 404, and we need to close the session
close(session); close(session);
} }
};
} }
private KeycloakSession configureContextualData(RoutingContext context) { private KeycloakSession configureContextualData(RoutingContext context) {