How to prevent Spring Boot daemon/server application from closing/shutting down immediately?
Asked Answered
E

9

30

My Spring Boot application is not a web server, but it's a server using custom protocol (using Camel in this case).

But Spring Boot immediately stops (gracefully) after started. How do I prevent this?

I'd like the app to stop if Ctrl+C or programmatically.

@CompileStatic
@Configuration
class CamelConfig {

    @Bean
    CamelContextFactoryBean camelContext() {
        final camelContextFactory = new CamelContextFactoryBean()
        camelContextFactory.id = 'camelContext'
        camelContextFactory
    }

}
Elbertelberta answered 19/1, 2015 at 3:59 Comment(1)
How do you expose your end point, can you share some code?Unfathomable
P
23

As of Apache Camel 2.17 there is a cleaner answer. To quote http://camel.apache.org/spring-boot.html:

To keep the main thread blocked so that Camel stays up, either include the spring-boot-starter-web dependency, or add camel.springboot.main-run-controller=true to your application.properties or application.yml file.

You will want the following dependency too:

<dependency> <groupId>org.apache.camel</groupId> <artifactId>camel-spring-boot-starter</artifactId> <version>2.17.0</version> </dependency>

Clearly replace <version>2.17.0</version> or use the camel BOM to import dependency-management information for consistency.

Preterhuman answered 18/5, 2016 at 15:1 Comment(0)
E
38

I found the solution, using org.springframework.boot.CommandLineRunner + Thread.currentThread().join(), e.g.: (note: code below is in Groovy, not Java)

package id.ac.itb.lumen.social

import org.slf4j.LoggerFactory
import org.springframework.boot.CommandLineRunner
import org.springframework.boot.SpringApplication
import org.springframework.boot.autoconfigure.SpringBootApplication

@SpringBootApplication
class LumenSocialApplication implements CommandLineRunner {

    private static final log = LoggerFactory.getLogger(LumenSocialApplication.class)

    static void main(String[] args) {
        SpringApplication.run LumenSocialApplication, args
    }

    @Override
    void run(String... args) throws Exception {
        log.info('Joining thread, you can press Ctrl+C to shutdown application')
        Thread.currentThread().join()
    }
}
Elbertelberta answered 19/1, 2015 at 8:49 Comment(6)
what is your main method? That doens't compile.Virtuous
@stealth Rabbi static void main(String[] args)Elbertelberta
OK, but look at main(). It looks like you're missing some parens. It does not compile. " SpringApplication.run LumenSocialApplication, args"Virtuous
@Stealth Rabbi I'll mention that my code is Groovy, not JavaElbertelberta
This will break integration tests that are using the SpringBootTest annotation.Diploblastic
This only works if your application is healthy. If it crashes it will hang instead of exiting, which is a problem.Thereafter
P
23

As of Apache Camel 2.17 there is a cleaner answer. To quote http://camel.apache.org/spring-boot.html:

To keep the main thread blocked so that Camel stays up, either include the spring-boot-starter-web dependency, or add camel.springboot.main-run-controller=true to your application.properties or application.yml file.

You will want the following dependency too:

<dependency> <groupId>org.apache.camel</groupId> <artifactId>camel-spring-boot-starter</artifactId> <version>2.17.0</version> </dependency>

Clearly replace <version>2.17.0</version> or use the camel BOM to import dependency-management information for consistency.

Preterhuman answered 18/5, 2016 at 15:1 Comment(0)
A
16

An example implementation using a CountDownLatch:

@Bean
public CountDownLatch closeLatch() {
    return new CountDownLatch(1);
}

public static void main(String... args) throws InterruptedException {
    ApplicationContext ctx = SpringApplication.run(MyApp.class, args);  

    final CountDownLatch closeLatch = ctx.getBean(CountDownLatch.class);
    Runtime.getRuntime().addShutdownHook(new Thread() {
        @Override
        public void run() {
            closeLatch.countDown();
        }
    });
    closeLatch.await();
}

Now to stop your application, you can look up the process ID and issue a kill command from the console:

kill <PID>
Atheistic answered 17/3, 2016 at 15:33 Comment(0)
P
5

Spring Boot leaves the task of running the application to the protocol around which the application is implemented. See, for example, this guide:

Also required are some housekeeping objects like a CountDownLatch to keep the main thread alive...

So the way of running a Camel service, for example, would to be to run Camel as a standalone application from your main Spring Boot application class.

Provencal answered 9/8, 2015 at 21:40 Comment(2)
the 'this guide' link is broken.Granddad
It appears Spring revamped their quides and the original article is not available any more.Provencal
R
5

All threads are completed, the program will close automatically. So, register an empty task with @Scheduled will create a loop thread to prevent shutdown.

file application.yml

spring:
  main:
    web-application-type: none

file DemoApplication.java

@SpringBootApplication
@EnableScheduling
public class DemoApplication {

   public static void main(String[] args) {
       SpringApplication.run(DemoApplication.class, args);
   }

}

file KeepAlive.java

@Component
public class KeepAlive {

   private static final Logger log = LoggerFactory.getLogger(ScheduledTasks.class);
   private static final SimpleDateFormat dateFormat =  new SimpleDateFormat("HH:mm:ss");

   @Scheduled(fixedRate = 1 * 1000 * 60) // 1 minute
   public void reportCurrentTime() {
       log.info("Keepalive at time {}", dateFormat.format(new Date()));
   }
}
Reyesreykjavik answered 19/2, 2019 at 9:34 Comment(1)
This can be an answer and not a comment. Please read the rules.Xerxes
C
4

This is now made even simpler.

Just add camel.springboot.main-run-controller=true to your application.properties

Circumscription answered 6/4, 2019 at 16:43 Comment(0)
M
0

My project is NON WEB Spirng Boot. My elegant solution is create a daemon thread by CommandLineRunner. Then, Application do not shutdown immediately.

 @Bean
    public CommandLineRunner deQueue() {
        return args -> {
            Thread daemonThread;
            consumer.connect(3);
            daemonThread = new Thread(() -> {
                try {
                    consumer.work();
                } catch (InterruptedException e) {
                    logger.info("daemon thread is interrupted", e);
                }
            });
            daemonThread.setDaemon(true);
            daemonThread.start();
        };
    }
Mascon answered 19/4, 2018 at 6:57 Comment(0)
C
-3

To keep the java process alive when not deploying a web application set the webEnvironment property to false like so:

 SpringApplication sa = new SpringApplication();
 sa.setWebEnvironment(false); //important
 ApplicationContext ctx = sa.run(ApplicationMain.class, args);
Charo answered 1/8, 2016 at 8:51 Comment(0)
W
-5

for springboot app to run continously it has to be run in a container, otherwise it is just like any java app all threads are done it finishes, you can add

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

and it will turn it into webapp, if not you are responsible keeping it alive in your implementation

Wilow answered 19/1, 2015 at 4:33 Comment(1)
Like I said above, it's not a web server. So my question is... how do I simulate Tomcat's behavior? Do I stall the main thread or something like that? What's the "official" way to do this?Elbertelberta

© 2022 - 2024 — McMap. All rights reserved.