0

I've a micronaut cli application.

Some command are long running process that I want to monitor with micronaut endpoints

Since when you are on a cli app, micronaut detect and don't launch the webserver.

In this long running command, I've added this to start the webserver :


        applicationContext
            .findBean(EmbeddedServer.class)
            .ifPresent(server -> {
                // start server
                long start = System.currentTimeMillis();
                server.start();

                log.info(
                    "Startup completed in {} ms. Server Running: {}",
                    System.currentTimeMillis() - start,
                    server.getURL()
                );

                // force exit
                if (server.isForceExit()) {
                    System.exit(0);
                }
            });

Most of the code come from Micronaut.java.

The full command source code:

package test;

import io.micronaut.configuration.picocli.PicocliRunner;
import io.micronaut.context.ApplicationContext;
import io.micronaut.runtime.server.EmbeddedServer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import picocli.CommandLine;

import javax.inject.Inject;
import java.util.concurrent.Callable;

@CommandLine.Command(
    name = "test",
    mixinStandardHelpOptions = true,
    subcommands = {
        TestApp.TestServer.class,
    }
)
public class TestApp implements Callable<Object> {
    public static void main(String[] args) throws Exception {
        PicocliRunner.call(TestApp.class, args);
    }

    @Override
    public Object call() throws Exception {
        return PicocliRunner.call(TestApp.class, "--help");
    }

    @CommandLine.Command(
        name = "server",
        description = "Start a webserver"
    )
    public static class TestServer implements Runnable {
        @Inject
        ApplicationContext applicationContext;

        Logger log = LoggerFactory.getLogger(TestServer.class);

        @Override
        public void run() {
            applicationContext
                .findBean(EmbeddedServer.class)
                .ifPresent(server -> {
                    // start server
                    long start = System.currentTimeMillis();
                    server.start();

                    log.info(
                        "Startup completed in {} ms. Server Running: {}",
                        System.currentTimeMillis() - start,
                        server.getURL()
                    );

                    // force exit
                    if (server.isForceExit()) {
                        System.exit(0);
                    }
                });
        }
    }
}

The webserver is starting well. I've added 2 endpoints, logger and health. Logger endpoint works well, but the health endpoint (like most every endpoint) failed with with this stacktrace : Full Stacktrace

io.reactivex.exceptions.UndeliverableException: The exception could not be delivered to the consumer because it has already canceled/disposed the flow or the exception has nowhere to go to begin with. Further reading: https://github.com/ReactiveX/RxJava/wiki/What's-different-in-2.0#error-handling | java.util.concurrent.RejectedExecutionException: Task java.util.concurrent.FutureTask@1f5e667f[Not completed, task = java.util.concurrent.Executors$RunnableAdapter@1615aa7e[Wrapped task = io.micronaut.http.context.ServerRequestContext$$Lambda$653/0x00000008406af040@5f7931cf]] rejected from java.util.concurrent.ThreadPoolExecutor@33dd1064[Terminated, pool size = 0, active threads = 0, queued tasks = 0, completed tasks = 0]
    at io.reactivex.plugins.RxJavaPlugins.onError(RxJavaPlugins.java:367)
...
Caused by: java.util.concurrent.RejectedExecutionException: Task java.util.concurrent.FutureTask@1f5e667f[Not completed, task = java.util.concurrent.Executors$RunnableAdapter@1615aa7e[Wrapped task = io.micronaut.http.context.ServerRequestContext$$Lambda$653/0x00000008406af040@5f7931cf]] rejected from java.util.concurrent.ThreadPoolExecutor@33dd1064[Terminated, pool size = 0, active threads = 0, queued tasks = 0, completed tasks = 0]
    at java.base/java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2055)
....
    at io.micronaut.scheduling.instrument.InstrumentedExecutorService.submit(InstrumentedExecutorService.java:89)
    at io.micronaut.core.async.publisher.AsyncSingleResultPublisher$ExecutorServiceSubscription.request(AsyncSingleResultPublisher.java:98)
    at io.reactivex.internal.operators.flowable.FlowableFlatMap$InnerSubscriber.onSubscribe(FlowableFlatMap.java:656)
    at io.micronaut.core.async.publisher.AsyncSingleResultPublisher.subscribe(AsyncSingleResultPublisher.java:59)
...
    at io.reactivex.Flowable.subscribe(Flowable.java:14805)
    ... 38 more
Exception in thread "nioEventLoopGroup-1-4" io.reactivex.exceptions.UndeliverableException: The exception could not be delivered to the consumer because it has already canceled/disposed the flow or the exception has nowhere to go to begin with. Further reading: https://github.com/ReactiveX/RxJava/wiki/What's-different-in-2.0#error-handling | java.util.concurrent.RejectedExecutionException: Task java.util.concurrent.FutureTask@1f5e667f[Not completed, task = java.util.concurrent.Executors$RunnableAdapter@1615aa7e[Wrapped task = io.micronaut.http.context.ServerRequestContext$$Lambda$653/0x00000008406af040@5f7931cf]] rejected from java.util.concurrent.ThreadPoolExecutor@33dd1064[Terminated, pool size = 0, active threads = 0, queued tasks = 0, completed tasks = 0]
...
    at io.micronaut.http.context.ServerRequestTracingPublisher.lambda$subscribe$0(ServerRequestTracingPublisher.java:52)
    at io.micronaut.http.context.ServerRequestContext.with(ServerRequestContext.java:52)
    at io.micronaut.http.context.ServerRequestTracingPublisher.subscribe(ServerRequestTracingPublisher.java:52)
    at io.micronaut.core.async.publisher.Publishers.lambda$map$2(Publishers.java:133)
...
    at java.base/java.lang.Thread.run(Thread.java:834)
Caused by: java.util.concurrent.RejectedExecutionException: Task java.util.concurrent.FutureTask@1f5e667f[Not completed, task = java.util.concurrent.Executors$RunnableAdapter@1615aa7e[Wrapped task = io.micronaut.http.context.ServerRequestContext$$Lambda$653/0x00000008406af040@5f7931cf]] rejected from java.util.concurrent.ThreadPoolExecutor@33dd1064[Terminated, pool size = 0, active threads = 0, queued tasks = 0, completed tasks = 0]
    ... 38 more
2019-10-11 17:18:50,689 WARN  nioEventLoopGroup-1-4    i.n.u.c.AbstractEventExecutor        A task raised an exception. Task: io.reactivex.internal.schedulers.ExecutorScheduler$ExecutorWorker@7ebe5c10
java.lang.NullPointerException: Actually not, but can't throw other exceptions due to RS
    at io.reactivex.Flowable.subscribe(Flowable.java:14814)
...
    at java.base/java.lang.Thread.run(Thread.java:834)
Caused by: java.util.concurrent.RejectedExecutionException: Task java.util.concurrent.FutureTask@1f5e667f[Not completed, task = java.util.concurrent.Executors$RunnableAdapter@1615aa7e[Wrapped task = io.micronaut.http.context.ServerRequestContext$$Lambda$653/0x00000008406af040@5f7931cf]] rejected from java.util.concurrent.ThreadPoolExecutor@33dd1064[Terminated, pool size = 0, active threads = 0, queued tasks = 0, completed tasks = 0]
    at java.base/java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2055)
    at java.base/java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:825)
    at java.base/java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1355)
    at java.base/java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:118)
    at io.micronaut.scheduling.instrument.InstrumentedExecutorService.submit(InstrumentedExecutorService.java:89)
    at io.micronaut.core.async.publisher.AsyncSingleResultPublisher$ExecutorServiceSubscription.request(AsyncSingleResultPublisher.java:98)
    at io.reactivex.internal.operators.flowable.FlowableFlatMap$InnerSubscriber.onSubscribe(FlowableFlatMap.java:656)
    at io.micronaut.core.async.publisher.AsyncSingleResultPublisher.subscribe(AsyncSingleResultPublisher.java:59)
    at io.reactivex.internal.operators.flowable.FlowableFlatMap$MergeSubscriber.onNext(FlowableFlatMap.java:163)
    at io.reactivex.internal.operators.flowable.FlowableFromIterable$IteratorSubscription.slowPath(FlowableFromIterable.java:236)
    at io.reactivex.internal.operators.flowable.FlowableFromIterable$BaseRangeSubscription.request(FlowableFromIterable.java:124)
    at io.reactivex.internal.operators.flowable.FlowableFlatMap$MergeSubscriber.onSubscribe(FlowableFlatMap.java:117)
    at io.reactivex.internal.operators.flowable.FlowableFromIterable.subscribe(FlowableFromIterable.java:69)
    at io.reactivex.internal.operators.flowable.FlowableFromIterable.subscribeActual(FlowableFromIterable.java:47)
    at io.reactivex.Flowable.subscribe(Flowable.java:14805)
    ... 38 common frames omitted

Any clue to do this ?

tchiot.ludo
  • 915
  • 1
  • 9
  • 20
  • 1
    From the trace it looks like the server may have stopped or it wasn't started successfully. If you want to provide an example that reproduces the issue in an issue report please let us know – Graeme Rocher Oct 14 '19 at 08:25
  • Issue created here : https://github.com/micronaut-projects/micronaut-picocli/issues/9 – tchiot.ludo Oct 14 '19 at 08:37

1 Answers1

0

Thanks to Graeme Rocher that give the right direction here : https://github.com/micronaut-projects/micronaut-picocli/issues/9.

Starting the webserver from a cli is the right way:

applicationContext
            .findBean(EmbeddedServer.class)
            .ifPresent(server -> {
                // start server
                long start = System.currentTimeMillis();
                server.start();
             });

But you need to take care that your Command must keep the whole logic on the main thread. In case of multithreaded application, the server will be shutdown if you are not waiting for all the thread in main command

tchiot.ludo
  • 915
  • 1
  • 9
  • 20