-
Notifications
You must be signed in to change notification settings - Fork 0
feat: SSE 서비스 운영 상태 정의 로직 구현 #205
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
base: main
Are you sure you want to change the base?
Changes from all commits
2596d39
66b6bed
7dd19ce
8121323
3fffe02
b9eecbd
9fd96f4
d72fd31
43c3d1f
c5ddc3b
8cee796
bff7473
bd3b4a7
92f831b
91083e2
4bb883c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| package kr.allcll.backend.admin.seat; | ||
|
|
||
| public enum SeatStreamStatus { | ||
| LIVE("과목의 여석을 실시간으로 볼 수 있어요."), | ||
| PRESEAT("전체 학년 여석 탭을 이용해 주세요."), | ||
| IDLE("과목 실시간 여석 제공 전이에요. 서비스가 시작되면 알림을 드릴게요."), | ||
| ERROR("서비스 점검 중이에요. 조금만 기다려주세요."); | ||
|
|
||
| private final String message; | ||
|
|
||
| SeatStreamStatus(String message) { | ||
| this.message = message; | ||
| } | ||
|
|
||
| public String getMessage() { | ||
| return message; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| package kr.allcll.backend.admin.seat; | ||
|
|
||
| import java.util.Objects; | ||
| import kr.allcll.backend.admin.seat.dto.SeatStreamStatusResponse; | ||
| import kr.allcll.backend.support.sse.SseEventBuilderFactory; | ||
| import kr.allcll.backend.support.sse.SseService; | ||
| import lombok.RequiredArgsConstructor; | ||
| import org.springframework.stereotype.Service; | ||
|
|
||
| @Service | ||
| @RequiredArgsConstructor | ||
| public class SeatStreamStatusService { | ||
|
|
||
| private final SseService sseService; | ||
| public final SeatStreamStatusStore seatStreamStatusStore; | ||
|
|
||
| public void updateSeatStreamStatus(SeatStreamStatus newStatus) { | ||
| SeatStreamStatus currentStatus = seatStreamStatusStore.getCurrentStatus(); | ||
| if (Objects.equals(currentStatus, newStatus)) { | ||
| return; | ||
| } | ||
| seatStreamStatusStore.updateCurrentStatus(newStatus); | ||
|
|
||
| SeatStreamStatusResponse sseStatusResponse = getSeatStreamStatusResponse(newStatus); | ||
| sseService.propagate(SseEventBuilderFactory.EVENT_SEAT_STREAM_STATUS, sseStatusResponse); | ||
| } | ||
|
|
||
| private SeatStreamStatusResponse getSeatStreamStatusResponse(SeatStreamStatus newStatus) { | ||
| return SeatStreamStatusResponse.of( | ||
| newStatus.name().toLowerCase(), | ||
| newStatus.getMessage() | ||
| ); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| package kr.allcll.backend.admin.seat; | ||
|
|
||
| import org.springframework.stereotype.Component; | ||
|
|
||
| @Component | ||
| public class SeatStreamStatusStore { | ||
|
|
||
| private volatile SeatStreamStatus currentStatus; | ||
|
|
||
| public SeatStreamStatusStore() { | ||
| this.currentStatus = SeatStreamStatus.IDLE; | ||
| } | ||
|
|
||
| public SeatStreamStatus getCurrentStatus() { | ||
| return currentStatus; | ||
| } | ||
|
|
||
| public void updateCurrentStatus(SeatStreamStatus newStatus) { | ||
| this.currentStatus = newStatus; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| package kr.allcll.backend.admin.seat.dto; | ||
|
|
||
| public record SeatCrawlingStatusResponse( | ||
| boolean isActive | ||
| ) { | ||
|
|
||
| public static SeatCrawlingStatusResponse of(boolean isActive) { | ||
| return new SeatCrawlingStatusResponse(isActive); | ||
| } | ||
| } |
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| package kr.allcll.backend.admin.seat.dto; | ||
|
|
||
| public record SeatStreamStatusResponse( | ||
| String status, | ||
| String message | ||
| ) { | ||
|
|
||
| public static SeatStreamStatusResponse of(String status, String message) { | ||
| return new SeatStreamStatusResponse(status, message); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,7 +2,8 @@ | |
|
|
||
| import java.io.IOException; | ||
| import java.util.List; | ||
| import kr.allcll.backend.support.sse.dto.SseStatusResponse; | ||
| import kr.allcll.backend.admin.seat.SeatStreamStatus; | ||
| import kr.allcll.backend.admin.seat.SeatStreamStatusStore; | ||
| import lombok.RequiredArgsConstructor; | ||
| import lombok.extern.slf4j.Slf4j; | ||
| import org.springframework.stereotype.Service; | ||
|
|
@@ -15,12 +16,20 @@ | |
| public class SseService { | ||
|
|
||
| private final SseEmitterStorage sseEmitterStorage; | ||
| private final SeatStreamStatusStore seatStreamStatusStore; | ||
|
|
||
| public SseEmitter connect(String token) { | ||
| SseEmitter sseEmitter = createSseEmitter(); | ||
| sseEmitterStorage.add(token, sseEmitter); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Because Useful? React with 👍 / 👎. |
||
|
|
||
| SseEventBuilder initialEvent = SseEventBuilderFactory.createInitialEvent(); | ||
| sendEvent(sseEmitter, initialEvent); | ||
|
|
||
| SeatStreamStatus seatStreamStatus = seatStreamStatusStore.getCurrentStatus(); | ||
| SseEventBuilder initialSeatStreamStatusEvent = SseEventBuilderFactory.createInitialSeatStreamStatusEvent( | ||
| seatStreamStatus); | ||
| sendEvent(sseEmitter, initialSeatStreamStatusEvent); | ||
|
|
||
| return sseEmitter; | ||
| } | ||
|
|
||
|
|
@@ -54,9 +63,4 @@ private void sendEvent(SseEmitter sseEmitter, SseEventBuilder eventBuilder) { | |
| public List<String> getConnectedTokens() { | ||
| return sseEmitterStorage.getUserTokens().stream().toList(); | ||
| } | ||
|
|
||
| public SseStatusResponse isConnected(String token) { | ||
| boolean isConnected = sseEmitterStorage.getEmitter(token).isPresent(); | ||
| return SseStatusResponse.of(isConnected); | ||
| } | ||
| } | ||
This file was deleted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This sets the global stream status to
ERRORon any singleCrawlerAllcllException, but the commit only transitions back toLIVEwhen an admin explicitly starts crawling again. During an active scheduler run, later successful polls do not restoreLIVE, so one transient API failure can leave all current and newly connected clients seeing a persistent error state that no longer matches actual service health.Useful? React with 👍 / 👎.