Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Terminated Spring Boot App in Eclipse - Shutdown hook not called

I have a Spring Boot + Spring Data Redis/KeyValue project. I setup a Spring profile to run the application with all dependencies embedded. So at startup, I launch an embedded Redis Server. Everything works fine when I start it in Eclipse, except that I would like the Redis server to be stopped when I stop the Spring Boot application. So I setup several shutdown hooks, however they are not called when I terminate the application from Eclipse.

They are similar questions on SO, I created this one hoping there would be a Redis solution. Also none of these similar questions are specific to Spring Boot.

I tried many things:

  • Spring Boot's ExitCodeGenerator;
  • DisposableBean;
  • @PreDestroy;
  • I tried a ShutdownHook (after @mp911de's answer)

None of them are called.

Perhaps there is a Redis option, timeout, keep alive.. something outside the box I am not aware of ? How can I ensure that the Redis Server is stopped when my Spring Boot app is abruptly stopped ?

=> I saw this Embedded Redis for spring boot, but @PreDestroy is just not called when killing the application unexpectedly.

Here are some of the similar questions:

  • Shutdown hook doesn't work in Eclipse
    • How to get shutdown hook to execute on a process launched from Eclipse
    • What is the correct way to add a Shutdown Hook for an Eclipse RCP application?

I also saw this post on eclipse.org discussing how shutdown hook is not called when stopping an application from eclipse: Graceful shutdown of Java Applications


Here's all my relevant code:

Component to start the embedded Redis server at startup (With my attempts to stop it too!!):

@Component
public class EmbeddedRedis implements ExitCodeGenerator, DisposableBean{

    @Value("${spring.redis.port}")
    private int redisPort;

    private RedisServer redisServer;

    @PostConstruct
    public void startRedis() throws IOException {
        redisServer = new RedisServer(redisPort);
        redisServer.stop();
        redisServer.start();
    }

    @PreDestroy
    public void stopRedis() {
        redisServer.stop();
    }

    @Override
    public int getExitCode() {
        redisServer.stop();
        return 0;
    }

    @Override
    public void destroy() throws Exception {
        redisServer.stop();
    }
}

application.properties:

spring.redis.port=6379

Spring Boot App:

@SpringBootApplication
@EnableRedisRepositories
public class Launcher {

    public static void main(String[] args){
        new SpringApplicationBuilder() //
        .sources(Launcher.class)//
        .run(args);
    }

    @Bean
    public RedisTemplate<String, Model> redisTemplate() {
        RedisTemplate<String, Model> redisTemplate = new RedisTemplate<String, Model>();
        redisTemplate.setConnectionFactory(jedisConnectionFactory());
        return redisTemplate;
    }


    @Bean
    public JedisConnectionFactory jedisConnectionFactory() {
        JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory();
        jedisConnectionFactory.setHostName("localhost");
        return jedisConnectionFactory;
    }
}

Redis server (~ embedded) running:

$ ps -aef | grep redis
 ... /var/folders/qg/../T/1472402658070-0/redis-server-2.8.19.app *:6379  

The embedded Redis maven dependency:

<dependency>
    <groupId>com.github.kstyrc</groupId>
    <artifactId>embedded-redis</artifactId>
    <version>0.6</version>
</dependency>
like image 456
alexbt Avatar asked Aug 28 '16 17:08

alexbt


2 Answers

When using SpringBoot and Eclipse, you can install the STS (Spring Tool Suite) eclipse plugin to achieve graceful shutdown.

Once installed, run the application as a "Spring Boot App" instead of regular "Java application" (Run/debug configurations)

Ensure that the checkbox "Enable Life Cycle Management" checkbox is checked and when you will click on the red square button to stop the application, it will perform a graceful shutdown instead of a hard kill.

Edit:

It's worth noticing that there are two "red square button". One in the "Launch" toolbar and one in the "Console" panel. The one in the launch toolbar still performs hard kill but the one in the console allows the graceful shutdown for spring-boot application (launched with STS)

like image 69
Ghurdyl Avatar answered Sep 21 '22 01:09

Ghurdyl


I had the same problem, though not with Redis. I wanted maximum portability so other developers don't have to add STS if they don't want to. You can add this to any Spring Boot application to offer clean shutdown. Here's what I did, elaborating on the OP's own answer.

Add this to your main class, or any @Configuration class:

    @Bean
    public ApplicationRunner systemExitListener() {
        return args -> {
            if (args.getOptionValues("exitListener") != null) {
                System.out.println("Press Enter to exit application");
                new Scanner(System.in).nextLine();
                System.out.println("Exiting");
                System.exit(0);
            }
        };
    }

Then in Eclipse (or in your IDE of choice, or even on the command line), add the argument --exitListener to activate the code. In Eclipse, that would be in Run Configurations, on the Arguments tab, in the Program Arguments box.

like image 20
Ben Ingle Avatar answered Sep 21 '22 01:09

Ben Ingle