NestJS를 사용하여 실시간 알림 시스템을 구축하는 방법을 소개하려 합니다.
이 글에서는 SSE(Server-Sent Events)를 활용하여 클라이언트와 서버 간의 실시간 통신을 구현하고, 알림 스트리밍 및 과거 알림 조회 기능을 다룹니다.
실시간 알림 스트리밍: 특정 사용자가 이벤트를 받을 때마다 실시간으로 알림 전송.
과거 알림 조회: 사용자가 놓친 알림을 DB에서 가져와 조회.
알림 업데이트: 사용자가 읽은 알림의 상태를 업데이트.
NotificationController는 클라이언트 요청을 처리하고, NotificationService와의 인터페이스 역할을 합니다.
@Sse('stream')
stream(@UserInfo() user: UserEntity): Observable<MessageEvent> {
console.log(`SSE 요청 수신 for userId: ${user.id}`);
return this.notificationService.getNotificationStream(user.id).pipe(
map((message: string) => {
return { data: { message } } as MessageEvent;
}),
);
}
NotificationService는 알림 생성, 관리 및 스트리밍 로직을 담당합니다.
async emitNotification(message: string, videoId: number) {
const foundChannel = await this.channelRepository.findOne({
where: { video: { id: videoId } },
relations: ['user'],
});
if (!foundChannel || !foundChannel.user) {
throw new NotFoundException('해당 사용자를 찾을 수 없습니다.');
}
const userId = foundChannel.user.id;
const notification = this.notificationRepository.create({ userId, message });
const savedNotification = await this.notificationRepository.save(notification);
this.eventEmitter.emit(`notification:${userId}`, {
message,
id: savedNotification.id,
});
}
getNotificationStream(userId: number): Observable<any> {
return new Observable<any>((subscriber) => {
const handler = (data: { message: string; id: number }) => {
subscriber.next(data);
};
this.eventEmitter.on(`notification:${userId}`, handler);
return () => {
this.eventEmitter.off(`notification:${userId}`, handler);
};
});
}
SSE (Server-Sent Events)는 서버가 클라이언트에 실시간 데이터를 단방향으로 보낼 수 있도록 하는 웹 표준입니다.
웹소켓과 달리 서버에서만 데이터를 푸시할 수 있으며, 다음과 같은 특징이 있습니다: