EZSET 프로젝트를 진행하면서 small-j와 함께 출석 파트를 담당했다. 출석 파트를 개발하는 과정을 기록해보려한다.
Socket 서버는 출석이 상태변경을 계속 기다리며 클라이언트가 출결 페이지 접속 시 attendance
room에 넣는다.
관리자가 출석을 시작한 경우 Socket 서버에게 상태변경을 알리고 서버는 출석이 종료될 때까지 attendace
room에 접속중인 클라이언트들에게 일정 시간 간격으로 계속 해서 현재 상태를 전달한다.
이미 출석이 시작된 상태에서 사용자가 attendance
room에 입장시 2번에서 socket 서버는 계속해서 현재 상태를 알리고 있으므로 바로 출석 코드를 입력할 수 있는 창을 볼 수 있게한다.
출석 시작과 동시에 타이머를 작동시켜 3분이 지나게되면 자동으로 출석상태를 종료로 업데이트 하고 클라이언트들에게 전달한다.
기존의 방식에서 2번 과정.(진행 중 일때 페이지로 들어온 사용자들에게 현재상태를 바로 알려주기 위해 지속적으로 emit methods 사용) 이럴필요가 절대 없없다!
사용자가 이미 출석이 진행중일 때 들어오더라도, 진행중이지 않을 때 들어오더라도 클라이언트에서 join
이벤트 발생시 attendance
Room에 집어넣고나서 서버에서 유지하고 있는 현재 상태를 보내주면 주기적으로 현재 상태를 보내줄 필요가 없어진다.
어떻게 보면 상당히 바보같은 설계였다. 이제라도 알아서 다행이다
출석체크는 최대 3분간 이어지고, 사용자가 40명이 페이지에서 계속 대기를 한다면 360 X 40 = 1440 번이나 불필요한 요청이 이루어 지고있게된다.
join 이벤트가 발생 했을 때 attendance
Room 에 넣은 후 이벤트를 발생시킨 socket.id로 현재 상태를 emit한다.
socket.on('join', function(data) {
socket.join(data.roomName)
io.to('attendance').emit('attendance', curState)
})
이 부분으로 인해 이전코드에서 지속적으로 emit을 해주던 부분을 효율적으로 개선 할 수 있었다.
//기존 코드
socket.on('start', function(data) {
var emitFlag = setInterval(function() {
io.to('attendance').emit('attendance', curState)
if (curState.flag == false) clearInterval(emitFlag)
}, 500)
setTimeout(function() {
if (curState.flag == true) {
var endMsg = {
flag: false,
}
curState.flag = false
io.to('attendance').emit('attendance', endMsg)
}
}, 300000)
})
//개선된 코드
socket.on('start', function(data) {
setTimeout(function() {
if (curState.flag == true) {
var msg = {
flag: false,
}
curState.flag = false
socket.broadcast.to('attendance').emit('attendance', msg)
}
}, 300000)
})
//socket io to Attendance
export const io = undefined
export async function initSocket(app, SOCKET_PORT) {
const server = require('http').createServer(app)
const io = require('socket.io')(server)
//Attendance State
var curState = {
flag: false,
}
//connect event
io.on('connection', function(socket) {
socket.on('join', function(data) {
socket.join(data.roomName)
io.to('attendance').emit('attendance', curState)
})
//attendance event lisner
socket.on('attendance', function(data) {
curState.flag = data.flag
var msg = {
flag: data.flag,
}
//broadcast changed state
socket.broadcast.to('attendance').emit('attendance', msg)
})
//setTimeout 3m when attendance start
socket.on('start', function(data) {
setTimeout(function() {
if (curState.flag == true) {
var msg = {
flag: false,
}
curState.flag = false
socket.broadcast.to('attendance').emit('attendance', msg)
}
}, 300000)
})
})
//start socket.io server
server.listen(SOCKET_PORT, function() {
console.log(`[socket io] server listening on port ${SOCKET_PORT}`) // eslint-disable-line no-console
})
}
프로젝트의 전체 코드는 EZSET github 에서 확인하실 수 있습니다.