View

회사에서 Dark Sky 서비스를 이용하다가 서비스 종료 된다는 사실을 알게됐다. 백엔드 엔지니어 동료분이 기상청 API로 새벽까지 수정해서 작업해주셨는데, 화면에서 총 16개 지역의 최저, 최고 기온을 알려줘야하다보니 백단에서 기상청 API을 16번 호출해야한다.

그러다보니 약 8초정도 되는 어마어마한 대기시간을 그냥 둘 수가 없어서 express 서버 하나 만들어 소캣 통신도 되고, Redis Cache도 사용할 수 있도록 CRA 구조에 추가했다.

(소캣은 모든 브라우저에서 애니메이션 일시 중지를 해야되는 요건때문에 추가했다.)

 

 

1. 로컬(서버)에 Redis Server 설치, 서비스 시작하기

brew install redis
brew services start redis

 

2. script 추가하기

scripts/server.js 파일 만들고 package.json script 수정

"scripts": {
   "start": "node scripts/start.js",
   "build": "GENERATE_SOURCEMAP=false node --max_old_space_size=4096 scripts/build.js",
   "test": "node scripts/test.js",
   "server": "node scripts/server.js"
 }

 

3. 모듈 설치

  • express
  • http
  • redis
  • socket.io
  • socket.io-client

4. server.js

  • express, http 모듈로 socket io 객체 만들기
  • socket connection 되면 redis에 값 꺼내서 브로드캐스팅하기
  • 값 변경하라는 메시지가 전달되면 redis 값 수정하고, 변경된 값 브로드캐스팅하기
  • GET 요청이 오면 Redis에 저장된 데이터 보내기
const express = require('express')
const app = express()
const server = require('http').createServer(app)
const port = process.env.CACHE || 3002
const redis = require('redis')
const client = redis.createClient({ host: 'localhost', port: 6379 })

const io = require('socket.io')(server, {
  path: '/socket.io',
  transports: ['websocket']
})

io.sockets.on('connection', socket => {
  console.info('**** Connected Cache Socket')

  const rotation = client.get('rotation')
  if (rotation !== null) {
    console.info(`**** Send Rotation Status ${rotation}`)
    socket.broadcast.emit('rotation', rotation)
  }

  socket.on('rotation', _rotation => {
    const rotation = client.get('rotation')

    console.log('원래값', rotation)
    console.log('바꾸는 값', _rotation)

    console.info(`**** Change rotation to ${_rotation}`)
    socket.broadcast.emit('rotation', _rotation)
    client.set('rotation', _rotation)
  })

  socket.on('weather', _weather => {
    client.sadd('weather', JSON.stringify(_weather))
  })

  socket.on('disconnect', reason => {
    console.info('**** Disconnect Cache Socket')
  })
})

app.all('/*', (req, res, next) => {
  res.header('Access-Control-Allow-Origin', '*')
  res.header('Access-Control-Allow-Headers', 'X-Requested-With')
  next()
})

app.get('/rotation', (req, res) => {
  const rotation = client.get('rotation')
  return res.status(200).json({ rotation })
})

app.get('/weather', (req, res) => {
  try {
    client.smembers('weather', (error, data) => {
      if (error) {
        res.status(400)
      }

      if (data === null || data.length < 1) {
        res.status(200).json({ result: false, data: null })
      }

      res.status(200).json(JSON.parse(data[0]))
    })
  } catch (e) {
    res.status(400)
  }
})

server.listen(port, () => {
  console.info(`**** Express Server Listen on ${port}`)
})

5. socket.js

  • 화면에서 사용하는 소캣 설정
import socketIOClient from 'socket.io-client'

const SOCKET_URL = process.env.REACT_APP_URL || 'localhost'
const SERVER_PORT = process.env.REACT_APP_PORT || '3002'

export default class Socket {
  static instance = null

  static getInstance () {
    if (Socket.instance === null) {
      Socket.instance = socketIOClient('http://' + SOCKET_URL + ':' + SERVER_PORT, {
        path: '/socket.io',
        transports: ['websocket']
      })
    }
    return Socket.instance
  }
}

 

6. 화면에서 소캣 메시지 전송

import Socket from '../../helpers/socket'

const socket = Socket.getInstance()

socket.emit('rotation', _rotation)

 

끝~~

 

ps) Redis에 카프카처럼 토픽을 sub, pub 할수 있는 기능이 있다고 한다. 다음에 스터디 해보자!

Share Link
reply
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31