본문 바로가기

Backend/Spring

Spring Boot Test Can’t Start Redis Server

오류 메세지

Caused by: java.lang.RuntimeException: Can't start redis server. Check logs for details.
    at redis.embedded.AbstractRedisInstance.awaitRedisServerReady(AbstractRedisInstance.java:62)
    at redis.embedded.AbstractRedisInstance.start(AbstractRedisInstance.java:39)
    at redis.embedded.RedisServer.start(RedisServer.java:9)
    at org.hoongoin.interviewbank.config.TestRedisConfig.startRedis(TestRedisConfig.java:19)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:568)
    at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleElement.invoke(InitDestroyAnnotationBeanPostProcessor.java:389)
    at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor$LifecycleMetadata.invokeInitMethods(InitDestroyAnnotationBeanPostProcessor.java:333)
    at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.postProcessBeforeInitialization(InitDestroyAnnotationBeanPostProcessor.java:157)
    ... 104 common frames omitted

문제 상황

세부 설정이 다른 @SpringBootTest(classes={TestRedisConfig.class}) 실행시, Failed to load ApplicationContext, Can't start redis server. 에러가 터졌다.

테스트 전체 실행시 authentication 테스트가 Fail하고 클래스 단독 실행시에는 성공.

@TestConfiguration
public class TestRedisConfig {
    private RedisServer redisServer;
    @Value("${spring.redis.port}")
    private int port;

    @PostConstruct
    public void startRedis() {
        redisServer = new RedisServer(port);
        redisServer.start();
    }

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

Spring 애플리케이션에서 Redis를 사용하고 있어, testImplementation 'it.ozimov:embedded-redis:0.7.2' 를 사용해 SpringBootTest에서 임베디드 레디스를 사용하도록 만들었다.

원인

애플리케이션컨텍스트의 캐싱때문에, 클래스의 테스트가 끝날 때 마다 애플리케이션컨텍스트가 소멸되는 것이 아니다.

애플리케이션 컨텍스트가 소멸되지 않았는데, 새로운 애플리케이션 컨텍스트가 생성되면서, 레디스서버가 하나 더 생겼다. 레디스 서버가 이미 열려있는데, 동일한 포트로 또 레디스 서버를 열려다보니 이런 에러가 생겼다.

설정이 같은 애너테이션에 대해 스프링은 애플리케이션컨텍스트의 캐싱을 한다.

해결

  1. RuntimeException이 일어났을 때, 이미 레디스가 열려있다고 생각하고 넘어가준다.
    1. 다른 익셉션이 터졌을 때도 동일하게 해결하여, 레디스서버가 만들어지지 않을 수 있다.
@PostConstruct
    public void startRedis() {
        try {
            redisServer = new RedisServer(port);
            redisServer.start();
        } catch (Exception e) {
        }
    }
  1. 포트를 Random하게 만들어, 레디스 서버를 만들어준다. 그러면 새로운 애플리케이션을 시작할 때 마다 새로운 레디스 서버가 생긴다.
    1. 단점: 레디스 서버가 여러개 켜질 수 있다. 메모리를 많이 잡아먹는다.

1번을 통해 문제를 해결해줬다.

'Backend > Spring' 카테고리의 다른 글

같은 클래스 내에서 메소드 호출 시 AOP 적용 문제  (0) 2023.05.09
@Transactional 전파 전략  (0) 2023.05.07
DI와 IoC  (0) 2023.04.07
Spring Container와 Bean의 Lifecycle  (0) 2023.04.07
Spring Boot Controller Test  (0) 2023.04.07