Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[DEPLOYMENT] timeout, heartbeat, 액추에이터 추가했습니다. #216

Merged
merged 4 commits into from
Jun 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,9 @@ dependencies {

// redis
implementation 'org.springframework.boot:spring-boot-starter-data-redis'

// actuator
implementation 'org.springframework.boot:spring-boot-starter-actuator'
}

tasks.named('bootBuildImage') {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,21 @@
import com.skyhorsemanpower.auction.domain.RoundInfo;
import com.skyhorsemanpower.auction.repository.RoundInfoReactiveRepository;
import com.skyhorsemanpower.auction.repository.RoundInfoRepository;
import com.skyhorsemanpower.auction.status.AuctionTimeEnum;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.jdt.internal.compiler.IErrorHandlingPolicy;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Flux;
import reactor.core.publisher.SignalType;
import reactor.core.scheduler.Schedulers;

import java.time.Duration;
import java.util.concurrent.TimeoutException;

@Slf4j
@RestController
@RequiredArgsConstructor
Expand Down Expand Up @@ -48,13 +54,45 @@ public SuccessResponse<Object> offerBiddingPrice(
@Operation(summary = "경매 페이지 API", description = "경매 페이지에 보여줄 데이터 실시간 조회")
public Flux<RoundInfoResponseVo> auctionPage(
@PathVariable("auctionUuid") String auctionUuid) {
return roundInfoReactiveRepository.searchRoundInfo(auctionUuid).subscribeOn(Schedulers.boundedElastic())
Flux<RoundInfoResponseVo> roundInfoResponseVoFlux = roundInfoReactiveRepository.searchRoundInfo(auctionUuid)
.timeout(Duration.ofMinutes(AuctionTimeEnum.MINUTES_120.getMinute()))
.subscribeOn(Schedulers.boundedElastic())
.doOnError(error -> {
log.info("SSE error occured!! >>> {}", error.toString());
if (error instanceof TimeoutException) {
log.info("Timeout occurred about SSE!");
} else {
log.info("SSE error occured!! >>> {}", error.toString());
}
})
.onErrorResume(error -> {
// 에러 발생 시, 빈 Flux 객체를 반환
return Flux.empty();
if (error instanceof TimeoutException) {
log.info("Connection closed due to timeout");
// 에러 발생 시, 빈 Flux 객체를 반환
return Flux.empty();
}
// 다른 에러 발생 시, 빈 Flux 객체를 반환해서 연결 종료
return Flux.error(error);
}
);

// heartbeat 스트림으로 1분 주기로 확인
Flux<RoundInfoResponseVo> heartbeat = Flux.interval(Duration.ofMinutes(1))
.map(tick -> new RoundInfoResponseVo());

// 메시지 및 heartbeat 반환
return roundInfoResponseVoFlux.mergeWith(heartbeat)
.doOnSubscribe(sub -> log.info("Subscribed to roundInfoResponseVo and heartbeat streams"))
.doFinally(signalType -> {
// 디버그 용 로그
if (signalType == SignalType.ON_COMPLETE) {
log.info("Connection completed.");
} else if (signalType == SignalType.ON_ERROR) {
log.info("Connection terminated due to error.");
} else {
log.info("Connection terminated by signal type: {}", signalType);
}
//todo
// 자원 해제 메서드 추가 필요
});
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.skyhorsemanpower.auction.status;

import lombok.Getter;
import lombok.RequiredArgsConstructor;

@Getter
@RequiredArgsConstructor
public enum AuctionTimeEnum {
MINUTES_01(1),
MINUTES_30(30),
MINUTES_60(60),
MINUTES_120(120);

private final int minute;
}
Loading