이전에 작성한 WebSocket을 활용한 실시간 경매 서버에 이어 경매종료를 확인해 자동으로 상태를 변경하는 스케줄링 서버를 만들어보자
WebSocket을 활용한 실시간 경매 서버 구현
파이널 프로젝트에 저희 팀으 선정한 주제는 "실시간 경매를 활용한 리셀"프로젝트입니다 실시간 경매 프로젝트를 진행하면서 제가 맡게된 파트는 웹소캣을 활용한 실시간 경매방과 자동 상태
cork-7.tistory.com
스케줄링 서버는 웹소켓 서버에서 경매를 생성할 때 메인에서 요청한 종료시간에 맞춰 레디스에 지정한 TTL 만료를 감지하여 다시 웹소캣에 전달하는 역할을 한다
왜 웹소캣 서버에서 만료를 감지 하지 않고 따로 서버를 만들어야할까?
처음부터 스케줄링 서버를 만들려고 진행한것은 아니였다. 다만 웹소캣 서버를 진행하면서 내부 로직이 점차 커지면서 웹소캣서버가 해야할 로직이 정해지고 그 외의 것을 부담하기위해 상태를 확인하고 전달하는 스케줄링 서버를 구현하기로 했다.
RedisConfig
Redis의 TTL(Key만료 이벤트)를 감지하기 위한 설정이다
@Configuration
@RequiredArgsConstructor
public class RedisConfig {
@Bean
public RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory, RedisExpirationListener listener) {
RedisMessageListenerContainer container = new RedisMessageListenerContainer();
container.setConnectionFactory(connectionFactory);
container.addMessageListener(listener, new ChannelTopic("__keyevent@0__:expired"));
return container;
}
@Bean
public WebClient webClient() {
return WebClient.builder().build();
}
}
- RedisMessageListenerContainer는 Redis Pub/Sub 구조에서 메시지를 **리스닝(수신)**하는 역할을 한다.
- __keyevent@0__:expired는 Redis에서 TTL이 만료된 키를 알려주는 특별한 채널이다.
- RedisExpirationListener 클래스가 이 채널로부터 메시지를 받아 처리하게 된다.
- 또한 웹소켓 서버에 비동기 요청을 보내기 위해 WebClient를 Bean으로 등록
⌘ WebClient는 스케줄링 서버가 웹소켓 서버에 HTTP 비동기 요청을 보내기 위해 사용하는 HTTP 클라이언트이다 ⌘
RedisExpirationListener
실제로 Redis TTL 만료 이벤트를 감지하고 후속 작업을 실행하는 로직
@Slf4j
@Service
@RequiredArgsConstructor
public class RedisExpirationListener implements MessageListener {
private final WebClient webClient;
@Override
public void onMessage(Message message, byte[] patten) {
String expiredKey = message.toString();
log.info("TTL 만료 감지: {}", expiredKey);
if (expiredKey.startsWith("auction:end:")) {
String auctionId = expiredKey.split(":")[2];
String socketUrl = "http://localhost:8081/internal/auction/" + auctionId + "/winner";
webClient.post()
.uri(socketUrl)
.retrieve()
.toBodilessEntity()
.subscribe(
success -> log.info("웹소캣 서버에 낙찰가 정보 전송 요청 완료: auctionId = {}", auctionId),
error -> log.error("웹소캣 서버 요청 실패: auctionId = {}, error = {}", auctionId, error.getMessage())
);
}
}
}
- 예를 들어, "auction:end:10" 같은 키가 만료되면 해당 경매가 종료되었음을 뜻한다.
- 경매 ID를 파싱하여 웹소켓 서버에 HTTP POST 요청을 보낸다. 이 요청은 다음과 같은 의미다:
- "10번 경매가 종료되었으니, 낙찰자를 찾아서 메인 서버로 전달해줘!"
- WebClient의 .subscribe()를 사용해 비동기 방식으로 요청을 보내며, 스케줄링 서버는 응답을 기다리지 않고 다음 이벤트를 처리할 준비를 한다.
- 성공/실패 여부는 log를 통해 기록된다.
이렇게 코드를 작성했다면
이전에 설명한대로 아키텍처의 흐름에 따라 WebSocket 서버와 연결되며, 스케줄링 서버는 종료 알림만 보내고,
낙찰자 정보 전달은 WebSocket 서버의 AuctionEndService가 처리하도록 역할을 분리했다.
'내일배움캠프' 카테고리의 다른 글
[트러블 슈팅] Transaction Commit 전 서버에서 경매방이 생성되는 문제 (0) | 2025.04.30 |
---|---|
WebSocket을 활용한 실시간 경매 서버 구현 (0) | 2025.04.29 |