EZSET-전자출결-02-1-출석기능 개선하기(Socket.io)

Seok·2020년 12월 6일
0

EZSET

목록 보기
3/7
post-thumbnail

EZSET 프로젝트를 진행하면서 small-j와 함께 출석 파트를 담당했다. 출석 파트를 개발하는 과정을 기록해보려한다.


0. 기존의 방식

  1. Socket 서버는 출석이 상태변경을 계속 기다리며 클라이언트가 출결 페이지 접속 시 attendance room에 넣는다.

  2. 관리자가 출석을 시작한 경우 Socket 서버에게 상태변경을 알리고 서버는 출석이 종료될 때까지 attendace room에 접속중인 클라이언트들에게 일정 시간 간격으로 계속 해서 현재 상태를 전달한다.

  3. 이미 출석이 시작된 상태에서 사용자가 attendance room에 입장시 2번에서 socket 서버는 계속해서 현재 상태를 알리고 있으므로 바로 출석 코드를 입력할 수 있는 창을 볼 수 있게한다.

  4. 출석 시작과 동시에 타이머를 작동시켜 3분이 지나게되면 자동으로 출석상태를 종료로 업데이트 하고 클라이언트들에게 전달한다.


1. 반성

기존의 방식에서 2번 과정.(진행 중 일때 페이지로 들어온 사용자들에게 현재상태를 바로 알려주기 위해 지속적으로 emit methods 사용) 이럴필요가 절대 없없다!

사용자가 이미 출석이 진행중일 때 들어오더라도, 진행중이지 않을 때 들어오더라도 클라이언트에서 join 이벤트 발생시 attendance Room에 집어넣고나서 서버에서 유지하고 있는 현재 상태를 보내주면 주기적으로 현재 상태를 보내줄 필요가 없어진다.

어떻게 보면 상당히 바보같은 설계였다. 이제라도 알아서 다행이다

출석체크는 최대 3분간 이어지고, 사용자가 40명이 페이지에서 계속 대기를 한다면 360 X 40 = 1440 번이나 불필요한 요청이 이루어 지고있게된다.


2. 개선

  • join 이벤트 핸들러 개선

join 이벤트가 발생 했을 때 attendanceRoom 에 넣은 후 이벤트를 발생시킨 socket.id로 현재 상태를 emit한다.

socket.on('join', function(data) {
            socket.join(data.roomName)
            io.to('attendance').emit('attendance', curState)
        })

이 부분으로 인해 이전코드에서 지속적으로 emit을 해주던 부분을 효율적으로 개선 할 수 있었다.

  • start 이벤트 핸들러 개선 : setInterval 삭제
//기존 코드
 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)
            })

3. 전체 코드 (socket.js)

//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 에서 확인하실 수 있습니다.

profile
🦉🦉🦉🦉🦉

0개의 댓글