Skip to content

[TCK-Challenge] The ContextTckResource creates a non-managed executor service #377

Description

@jamezp

In the org.eclipse.microprofile.lra.tck.TckContextTests TCK the following two tests invoke a resource which submits threads on a non-managed executor service:

  • testAsync1Support()
  • testAsync2Support()

The methods are in the org.eclipse.microprofile.lra.tck.participant.api,ContextTckResource:

  • async1LRA()
  • asyncInvocationWithLRA()

In WildFly the tests use Narayana which has a io.narayana.lra.filter.ServerLRAFilter filter which is a CDI bean. Given the methods use a non-managed thread, the CDI context is not available and an exception is thrown:

07:17:47,687 WARN  [io.narayana.lra] (pool-13-thread-1) LRA025036: CDI Context not available: LRAParticipantData is not usable in this (probably async) context.
07:17:47,721 ERROR [org.jboss.resteasy.core.providerfactory.DefaultExceptionMapper] (pool-13-thread-1) RESTEASY002375: Error processing request PUT /tckcontexttests/context-tck-resource/async-response-lra - org.eclipse.microprofile.lra.tck.participant.api.ContextTckResource.async1LRA: org.jboss.weld.contexts.ContextNotActiveException: WELD-001303: No active contexts for scope type jakarta.enterprise.context.RequestScoped
	at org.jboss.weld.core@6.0.4.Final//org.jboss.weld.manager.BeanManagerImpl.getContext(BeanManagerImpl.java:671)
	at org.jboss.weld.core@6.0.4.Final//org.jboss.weld.bean.ContextualInstanceStrategy$DefaultContextualInstanceStrategy.getIfExists(ContextualInstanceStrategy.java:95)
	at org.jboss.weld.core@6.0.4.Final//org.jboss.weld.bean.ContextualInstanceStrategy$CachingContextualInstanceStrategy.getIfExists(ContextualInstanceStrategy.java:179)
	at org.jboss.weld.core@6.0.4.Final//org.jboss.weld.bean.ContextualInstance.getIfExists(ContextualInstance.java:64)
	at org.jboss.weld.core@6.0.4.Final//org.jboss.weld.bean.proxy.ContextBeanInstance.getInstance(ContextBeanInstance.java:86)
	at org.jboss.weld.core@6.0.4.Final//org.jboss.weld.bean.proxy.ProxyMethodHandler.invoke(ProxyMethodHandler.java:108)
	at org.jboss.resteasy.resteasy-cdi@7.0.3.Final//org.jboss.weld.generated.proxies.ws.rs.container.ResourceInfo$889195678$Proxy$_$$_WeldClientProxy.getResourceMethod(Unknown Source)
	at org.jboss.narayana.lra.lra-participant@1.2.0.Final//io.narayana.lra.filter.ServerLRAFilter.filter(ServerLRAFilter.java:603)
	at org.jboss.narayana.lra.lra-participant@1.2.0.Final//io.narayana.lra.filter.ServerLRAFilter$Proxy$_$$_WeldClientProxy.filter(Unknown Source)
	at org.jboss.resteasy.resteasy-core@7.0.3.Final//org.jboss.resteasy.core.interception.jaxrs.ContainerResponseContextImpl.filter(ContainerResponseContextImpl.java:342)
	at org.jboss.resteasy.resteasy-core@7.0.3.Final//org.jboss.resteasy.core.ServerResponseWriter.executeFilters(ServerResponseWriter.java:243)
	at org.jboss.resteasy.resteasy-core@7.0.3.Final//org.jboss.resteasy.core.ServerResponseWriter.writeNomapResponse(ServerResponseWriter.java:100)
	at org.jboss.resteasy.resteasy-core@7.0.3.Final//org.jboss.resteasy.core.ServerResponseWriter.writeNomapResponse(ServerResponseWriter.java:73)
	at org.jboss.resteasy.resteasy-core@7.0.3.Final//org.jboss.resteasy.core.SynchronousDispatcher.asynchronousDelivery(SynchronousDispatcher.java:479)
	at org.jboss.resteasy.resteasy-core@7.0.3.Final//org.jboss.resteasy.core.AbstractAsynchronousResponse.internalResume(AbstractAsynchronousResponse.java:179)
	at org.jboss.resteasy.resteasy-core@7.0.3.Final//org.jboss.resteasy.plugins.server.servlet.Servlet3AsyncHttpRequest$Servlet3ExecutionContext$Servlet3AsynchronousResponse.resume(Servlet3AsyncHttpRequest.java:90)
	at deployment.tckcontexttests.war//org.eclipse.microprofile.lra.tck.participant.api.ContextTckResource.lambda$async1LRA$0(ContextTckResource.java:248)
	at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:545)
	at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:328)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1090)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:614)
	at java.base/java.lang.Thread.run(Thread.java:1474)

In an EE container, unmanaged threads should not be used to invoke tasks that require container managed resources.

A fix might be an attempt to lookup a ManagedExecutorService and if not found, given it's not required in the core profile, then use a known custom executor service. Potentially something like:

public static ExecutorService threadPool() {
    ExecutorService executor = lookup("java:comp/DefaultManagedExecutorService");
    if (executor == null) {
        final ExecutorService delegate = new ThreadPoolExecutor(Math.max(5, Runtime.getRuntime().availableProcessors()), Integer.MAX_VALUE, 60L, TimeUnit.SECONDS,
            new LinkedBlockingQueue<>(), new ContextualThreadFactory("contextual-pool"));
    }
    return executor;
}
private static <T extends ExecutorService> T lookup(final String jndiName) {
    final Boolean performLookup = JNDI_LOOKUPS.get(jndiName);
    if (performLookup != null && performLookup) {
        try {
            // This could have some performance impact. However, we can't assume the context we're in, so we need
            // to look it up each time.
            return InitialContext.doLookup(jndiName);
        } catch (NamingException ignore) {
        } catch (Exception e) {
            LogMessages.LOGGER.failedToLookupManagedExecutorService(e, jndiName);
        }
    } else if (performLookup == null) {
        // Do one lookup and if not found assume it won't be in the future
        try {
            final T service = InitialContext.doLookup(jndiName);
            JNDI_LOOKUPS.put(jndiName, Boolean.TRUE);
            return service;
        } catch (NamingException ignore) {
        } catch (Exception e) {
            LogMessages.LOGGER.failedToLookupManagedExecutorService(e, jndiName);
        }
        JNDI_LOOKUPS.put(jndiName, Boolean.FALSE);
    }
    return null;
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions