-
Notifications
You must be signed in to change notification settings - Fork 4
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
[Feat] SSE 알림 서비스 구현 #122
[Feat] SSE 알림 서비스 구현 #122
Changes from 1 commit
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,36 @@ | ||
package com.kuit.agarang.domain.notification.controller; | ||
|
||
import com.kuit.agarang.domain.notification.model.SseEmitters; | ||
import com.kuit.agarang.global.common.exception.exception.BusinessException; | ||
import com.kuit.agarang.global.common.model.dto.BaseResponseStatus; | ||
import lombok.RequiredArgsConstructor; | ||
import lombok.extern.slf4j.Slf4j; | ||
import org.springframework.http.MediaType; | ||
import org.springframework.web.bind.annotation.GetMapping; | ||
import org.springframework.web.bind.annotation.RestController; | ||
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; | ||
|
||
import java.io.IOException; | ||
|
||
@Slf4j | ||
@RestController | ||
@RequiredArgsConstructor | ||
public class SseController { | ||
|
||
private final SseEmitters sseEmitters; | ||
|
||
@GetMapping(value = "/connect", produces = MediaType.TEXT_EVENT_STREAM_VALUE) | ||
public SseEmitter connect() { | ||
SseEmitter emitter = new SseEmitter(10 * 60 * 1000L); | ||
sseEmitters.add(emitter); | ||
try { | ||
emitter.send(SseEmitter.event() | ||
.name("connect") | ||
.data("connected!")); // 503에러 방지를 위한 더미데이터 | ||
} catch (IOException e) { | ||
emitter.completeWithError(e); | ||
throw new BusinessException(BaseResponseStatus.FAIL_CREATE_EMITTER); | ||
} | ||
return emitter; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
package com.kuit.agarang.domain.notification.model; | ||
|
||
import lombok.extern.slf4j.Slf4j; | ||
import org.springframework.stereotype.Component; | ||
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; | ||
|
||
import java.io.IOException; | ||
import java.util.List; | ||
import java.util.concurrent.CopyOnWriteArrayList; | ||
|
||
@Slf4j | ||
@Component | ||
public class SseEmitters { | ||
private final List<SseEmitter> emitters = new CopyOnWriteArrayList<>(); | ||
|
||
public SseEmitter add(SseEmitter emitter) { | ||
this.emitters.add(emitter); | ||
log.info("new emitter added: {}", emitter); | ||
log.info("emitter list size: {}", emitters.size()); | ||
|
||
emitter.onCompletion(() -> { | ||
log.info("onCompletion callback"); | ||
this.emitters.remove(emitter); | ||
}); | ||
|
||
emitter.onTimeout(() -> { | ||
log.info("onTimeout callback"); | ||
emitter.complete(); | ||
}); | ||
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.
그리고 onTimeout 핸들러에서는
|
||
|
||
return emitter; | ||
} | ||
|
||
public void sendNotification(String message) { | ||
emitters.forEach(emitter -> { | ||
try { | ||
emitter.send(SseEmitter.event() | ||
.name("notification") | ||
.data(message)); | ||
log.info("Notification sent: {}", message); | ||
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. 음악 생성의 경우 알림 1회 전송이 끝인데, 알림 구독을 취소하는(emitters 맵에서 삭제하는) 로직은 없어도 되나요?? 만약 구독 취소를 구현해야 한다면 유지보수를 위해서 따로 구독취소 컨트롤러를 생성하면 좋을 것 같아요. (n회 알림이 필요한 경우 수정하지 않아도되기 때문에) |
||
} catch (IOException e) { | ||
log.error("Error sending notification: {}", e.getMessage()); | ||
emitter.complete(); | ||
} | ||
}); | ||
} | ||
} |
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.
연결 시에 회원 식별값에 대한 정보 없이도 해당 기기로 알림이 갈 수 있나요??
음악 생성이 비동기로 진행되기 때문에 여러 구독이 발생할 수 있고,
구독된 이벤트 중 특정 이벤트만 발생시켜야 한다면 식별정보가 필요할 것 같아서 여쭤봅니다!
만약 식별정보를 추가한다면
ConcurrentHashMap
같은 것도 좋을 것 같아요. (key
: memberId,value
: SseEmitter)