Quarkus: How to stop a Quarkus application

Created on 18 Apr 2019  路  9Comments  路  Source: quarkusio/quarkus

The documentation https://quarkus.io/guides/application-lifecycle-events-guide does not mention how a Quarkus application can be stopped from within; this is necessary for e.g. command line or job type applications.
The io.quarkus.runtime.Application class provides the necessary APIs, but cannot be injected.

Thanks for any clarification.

kinquestion pinned

Most helpful comment

That's an X/Y. We need a proper shutdown API. Also I don't think that observing StartupEvent is a proper long term solution for CLIs and jobs (I think there's an issue for this but I can't find it at the moment). I do have an upcoming design proposal for these use cases.

All 9 comments

Did you try System.exit ?

Yes, sorry, should have written that. That triggers Application's ShutdownHookThread and never returns from stateCond.awaitUninterruptibly(). That's why I thought the Application's state machine needs to be terminated via the Application's lifecylce methods ...

Just verified that with the most simple Quarkus application, System.exit does not happen:

@ApplicationScoped
public class AppLifecycleBean {
    private static final Logger LOGGER = LoggerFactory.getLogger("ListenerBean");
    void onStart(@Observes StartupEvent ev) {
        LOGGER.info("The application is starting...{}");
        new Thread(new Runnable() {
            @Override
            public void run() {
                LOGGER.info("About to system exit.");
                System.exit(0); // does not return
            }
        }).run();
    }
}

You must call Thread.start(), not Thread.run().

OK, so the findings are: If we System.exit() from the Thread from where we @Observed the Startup Event, System.exit() does not return:

public class AppLifecycleBean {
    private static final Logger LOGGER = LoggerFactory.getLogger("ListenerBean");
    void onStart(@Observes StartupEvent ev) {
        LOGGER.info("The application is starting...{}");
        LOGGER.info("About to system exit.");
        System.exit(0);
    }
}

But if we do it from a dedicated Thread, it works:

@ApplicationScoped
public class AppLifecycleBean {
    private static final Logger LOGGER = LoggerFactory.getLogger("ListenerBean");
    void onStart(@Observes StartupEvent ev) {
        LOGGER.info("The application is starting...{}");
        new Thread(new Runnable() {
            @Override
            public void run() {
                LOGGER.info("About to system exit.");
                System.exit(0);
            }
        }).start();
    }
}

Is this the expected behavior?`
Is it worth a note in the documentation?

It is expected behavior. exit never returns, thus it blocks the thread forever. The process doesn't exit until the thread pool shuts down, which cannot happen while threads are active. Thus, deadlock.

Thanks for your clarification & support. Since CLIs and Jobs will start their programs on @Observes StartupEvent, would it make sense to already dispatch these events from separate threads, so users don't have to figure out that they have to start their own threads to run their program? Or mention this fact in the documentation? Otherwise, feel free to close.

That's an X/Y. We need a proper shutdown API. Also I don't think that observing StartupEvent is a proper long term solution for CLIs and jobs (I think there's an issue for this but I can't find it at the moment). I do have an upcoming design proposal for these use cases.

Issue #2851 requests a proper shutdown API. Closing this issue now. Thanks!

Was this page helpful?
0 / 5 - 0 ratings