기록

[Spring Boot Kafka] 실행되지만 바로 종료되는 Spring Boot 애플리케이션 본문

코딩테스트/Java

[Spring Boot Kafka] 실행되지만 바로 종료되는 Spring Boot 애플리케이션

zyin 2025. 4. 18. 21:42

시작하면서

Kafka 기반의 오케스트레이터 마이크로서비스를 구성하는 과정에서, 애플리케이션이 정상적으로 빌드되고 실행되었음에도 불구하고 바로 종료되는 현상을 경험했다.
에러 메시지도 없고, 로그상으로는 성공적으로 기동된 것처럼 보이기 때문에 처음엔 의아할 수 있다. 해당 현상을 통해 Spring Boot 애플리케이션이 어떤 조건에서 프로세스를 유지하며, Kafka 기반 서비스에서는 어떤 요소들이 필수적인지를 정리해본다.


1. 문제 현상: 실행되지만 바로 종료되는 Spring Boot 애플리케이션

멀티모듈 기반 프로젝트에서 오케스트레이터 역할을 수행하는 모듈(service-membership-orchestrator)을 실행했더니 다음과 같은 로그만 출력되고 앱이 종료된다:

Started ServiceMembershipOrchestratorApplication in 4.3 seconds
BUILD SUCCESSFUL

Spring Boot 애플리케이션이 시작은 했지만, 곧바로 아무런 동작 없이 내려가버린다.


2. 원인 분석: Spring Boot는 아무것도 안 하면 내려간다

Spring Boot는 기본적으로 내부에 "계속 살아 있어야 할 이유"가 없으면 앱을 자동으로 종료한다.
이러한 조건에 해당하지 않으면 JVM이 유지될 이유가 없다고 판단한다:

✅ 앱이 살아 있는 조건

  • 내장 웹 서버가 실행 중일 경우 (spring-boot-starter-web)
  • Kafka 리스너가 등록되어 메시지를 대기 중일 경우 (@KafkaListener)
  • 스케줄링 작업이 주기적으로 수행될 경우 (@Scheduled)
  • 명시적으로 스레드를 유지할 경우 (Thread.currentThread().join() 등)

❌ 앱이 종료되는 조건

  • 위 조건 중 아무것도 충족하지 않을 경우, Spring Boot는 컨텍스트 초기화 후 곧바로 종료된다.

이 문제의 경우, Kafka 설정은 되어 있었지만 @KafkaListener가 등록되지 않았기 때문에 Spring Boot는 "아무것도 할 일이 없네?"라고 판단하고 종료한 것이다.


3. 흔한 오해: "웹 서버가 없어서 종료된 거 아닐까?"

많은 개발자들이 spring-boot-starter-web이 빠져 있어서 앱이 종료된다고 오해하곤 한다.
하지만 실제로는, 웹 서버가 필수인 것이 아니라 무언가 지속적으로 수행할 작업이 필요할 뿐이다.

즉, 웹 API가 전혀 필요하지 않은 마이크로서비스도 Kafka 리스너만 제대로 설정되어 있다면,
아무 문제 없이 프로세스를 유지하면서 메시지를 처리할 수 있다.


4. 해결 방법

1) Kafka 리스너 추가

@Component
public class UserInfoSyncOrchestrator {

    @KafkaListener(topics = "test-topic")
    public void consume(String message) {
        System.out.println("받은 메시지: " + message);
    }
}

이처럼 @KafkaListener로 메시지 소비 로직을 정의하면, Spring Boot는 Kafka 메시지를 기다리기 때문에 애플리케이션을 종료하지 않는다.
필요하다면 @EnableKafka도 @SpringBootApplication에 함께 추가한다:

@EnableKafka
@SpringBootApplication
public class ServiceMembershipOrchestratorApplication { ... }

5. 정리

  • Spring Boot 애플리케이션은 웹 서버가 없어도 Kafka 리스너가 등록되어 있으면 정상적으로 유지된다.
  • Kafka 기반 오케스트레이터는 spring-boot-starter-web 없이도 충분히 동작한다.
  • @KafkaListener는 단순한 메시지 소비 이상의 역할을 하며, 애플리케이션이 종료되지 않도록 유지하는 트리거 역할도 한다.
  • 멀티모듈 프로젝트에서는 JVM 버전이 모듈 간에 일치하지 않으면 의존성 해석 중 오류가 발생할 수 있으므로 주의해야 한다.

✅ 핵심 요약

Spring Boot는 웹 서버가 없더라도 Kafka 리스너가 있으면 애플리케이션을 종료하지 않는다.
오케스트레이터처럼 비동기 이벤트만 처리하는 서비스는 이를 활용해 효율적으로 구성할 수 있다.

Comments