
SSE
Server Sent Event는 클라이언트에서 요청 없이도 언제든지 서버가 새로운 데이터를 보내는 것이 가능한 방식을 말한다. 경매 시스템 같은 경우 클라이언트에서 경매가 언제 종료되는지 언제 경매가가 업데이트되는지 요청을 보내는 것이 아닌 서버에서 SSE 방식으로 정보를 보내주고 클라이언트는 응답을 받기만하면 된다.
- sse 모듈 설치
npm i sse
- sse.js
const SSE = require("sse");
module.exports = (server) => {
const sse = new SSE(server);
sse.on("connection", (client) => {
setInterval(() => {
client.send(Date.now().toString());
}, 1000);
});
};
`const sse = new SSE(익스프레스 서버)`로 객체를 생성해 `on`메서드로 이벤트를 등록해 사용하면 된다.
`connection` 이벤트 리스너는 클라이언트와 연결해 어떤 작업을 할지 정의하면 된다.
- main.html
{% extends 'layout.html' %} {% block content %}
<div class="timeline">
<h2>경매 진행 목록</h2>
<table id="good-list">
<tr>
<th>상품명</th>
<th>이미지</th>
<th>시작 가격</th>
<th>종료 시간</th>
<th>입장</th>
</tr>
{% for good in goods %}
<tr>
<td>{{good.name}}</td>
<td>
<img src="/img/{{good.img}}" />
</td>
<td>{{good.price}}</td>
<td class="time" data-start="{{good.createdAt}}">00:00:00</td>
<td>
<a href="/good/{{good.id}}" class="enter btn">입장</a>
</td>
</tr>
{% endfor %}
</table>
</div>
<script>
const es = new EventSource("/sse");
es.onmessage = function (e) {
document.querySelectorAll(".time").forEach((td) => {
const end = new Date(td.dataset.start); // 경매 시작 시간
const server = new Date(parseInt(e.data, 10));
end.setDate(end.getDate() + 1); // 경매 종료 시간
if (server >= end) {
// 경매가 종료되었으면
td.textContent = "00:00:00";
} else {
const t = end - server; // 경매 종료까지 남은 시간
const seconds = ("0" + Math.floor((t / 1000) % 60)).slice(-2);
const minutes = ("0" + Math.floor((t / 1000 / 60) % 60)).slice(-2);
const hours = ("0" + Math.floor((t / (1000 * 60 * 60)) % 24)).slice(-2);
td.textContent = hours + ":" + minutes + ":" + seconds;
}
});
};
</script>
{% endblock %}
- sse단점
sse 방식은 http/1.1에서 최대 6개 밖에 송신을 못한다.
스케쥴링
경매가 종료됐다면 낙찰자를 정해야한다. 이때 스케쥴링을 통해 낙찰자를 정해 그에 맞는 작업을 수행하면 된다.
- node-shcedule 스케쥴링 모듈 설치
npm i node-schedule
- controllers/index.js
const { Op } = require("sequelize");
const { Good, Auction, User, sequelize } = require("../models");
const schedule = require("node-schedule");
...
exports.createGood = async (req, res, next) => {
try {
const { name, price } = req.body;
const good = await Good.create({
OwnerId: req.user.id,
name,
img: req.file.filename,
price,
});
const end = new Date();
end.setDate(end.getDate() + 1); // 하루 뒤
const job = schedule.scheduleJob(end, async () => {
const success = await Auction.findOne({
where: { GoodId: good.id },
order: [["bid", "DESC"]],
});
await good.setSold(success.UserId);
await User.update(
{
money: sequelize.literal(`money - ${success.bid}`),
},
{
where: {
id: success.UserId,
},
}
);
});
job.on("error", console.error);
job.on("success", () => {
console.log(`${good.id} 스케쥴링 성공`);
});
res.redirect("/");
} catch (error) {
console.error(error);
next(error);
}
};
...
`schedule` 객체의 `scheduleJob` 메서드로 일정을 예약할 수 있다. 일정을 등록하면 `job`객체를 반환한다. `job.on('이벤트',콜백함수)` 를 통해 `error`이벤트와 스케줄링이 완료됐을때의 `success` 이벤트, 스케줄이 취소되는 `cancel` 이벤트, 스케줄링이 실행될 때 발생하는 `run` 이벤트등을 통해 콜백함수를 등록할 수 있다.
참고
Node.js 교과서 : 네이버 도서
네이버 도서 상세정보를 제공합니다.
search.shopping.naver.com
[개정3판] Node.js 교과서 - 기본부터 프로젝트 실습까지 강의 | 제로초(조현영) - 인프런
제로초(조현영) | 노드가 무엇인지부터, 자바스크립트 최신 문법, 노드의 API, npm, 모듈 시스템, 데이터베이스, 테스팅 등을 배우고 5가지 실전 예제로 프로젝트를 만들어 나갑니다. 클라우드에 서
www.inflearn.com
'Node.js' 카테고리의 다른 글
[Node.js 교과서]섹션 15 - AWS에 배포해보기 (0) | 2025.01.07 |
---|---|
[Node.js 교과서] 섹션 14- CLI 프로그램 만들기 (1) | 2024.12.15 |
[Node.js 교과서] 섹션 12 - 웹 소켓으로 실시간 데이터 전송하기 (0) | 2024.12.08 |
[Node.js 교과서] 섹션 11 - 노드 서비스 테스트 하기 (3) | 2024.12.05 |
[Node.js 교과서] 섹션 10 - 웹 API 서버 만들기 (0) | 2024.11.22 |