Websocket with Redux

arenacast·2022년 4월 25일
0
post-thumbnail
  • Redux 의 상태 업데이트 과정
  • Redux 에서 side effect (부수효과) handling
    1. Redux middleware
    2. websocket 방식에서의 문제점
  • Redux saga Channel

Redux store update 과정

redux 에서 스토어의 상태를 업데이트 하는 과정은 View(컴포넌트) 에서 특정 action(액션) 을 dispatch (디스페치) 하면 reducer 에서 이전 상태와 디스패치된 액션을 반영하여 새로운 상태를 반환하여 redux store 에 반영됩니다.

Redux 에서 side effect

먼저 여기에서 side effect 란 비동기 데이터 fetch, 네트워크 통신 등과 같이 외부의 영향을 받는 경우를 일컫습니다

redux 흐름상 액션 객체는 순수 자바스크립트 객체이며, reducer 는 순수함수로 구현되어집니다. 즉 side effect (부수효과) 를 handling 해주는 부분은 액션 생성함수나, 리듀서가 아닌 다른 부분이 되어야 될것입니다.

1. Redux middle ware

그 부수효과(side effect) 를 처리할수 있는 부분이 바로 redux 의 미들웨어입니다. 미들웨어는 액션이 디스패치 되고 리듀서로 반영되기 전인 부분에 해당합니다.

위 그림을 보시는 바와 같이 리덕스의 액션이 디스패치 되고 데이터 패치와 같은 비동기 부수효과를 핸들링 하고 난후에 디스패치된 액션이 리듀서에 반영되고 반영된 상태는 스토어에 업데이트 되는 방식으로 리덕스 내에서 부수효과를 핸들링 하게됩니다.

현재 저희 프론트앤드 픽앤고 팀에서는 데이터의 패치와 같은 부수효과는 모두 미들웨어를 커스터마이징하여 처리하고 있습니다. 즉 특정 data fetch action 이 디스패치 되면 비동기 처리 및 데이터 상태 반영을 redux 미들웨어 단에서 일괄적으로 처리하였습니다. 그래서 redux-thunk 나 redux-saga 와 같은 리덕스 미들웨어 라이브러리를 도입할 이유가 딱히 없었습니다.

하지만 websocket 과 같은 push 방식의 side effect(부수효과) 는 데이터 패치와 같은 비동기 처리와는 다른 얘기였습니다.

push VS pull

  • pull : 데이터 소비자가 데이터 공급자에게 요청하는 방식 (웹페이지 요청)
  • push : 데이터 공급자가 데이터 소비자에게 데이터 공급 (푸시 알림)

2. Websocket handling 에서의 문제점

픽앤고에서 웹소캣 메시지를 받아 핸들링하는 과정을 먼저 간단히 설명드리겠습니다.

한번에 받는 소켓메시지 속에는 9개의 빙고 셀(칸) 데이터, 8개의 빙고 라인에 대한 데이터 총 17(9+8)개의 데이터가 들어있습니다. 17개의 데이터가 하나의 소켓메시지에 담겨 오기 때문에 다시 17개의 데이터로 쪼개서 버퍼라는 공간에 담아두고 특정 시간간격(100ms) 으로 버퍼에서 데이터를 하나씩 Pop 하는 방식을 사용하였습니다. (아래 그림 참고)

버퍼에서 데이터를 가져오는 방식(pull 방식)은 데이터를 버퍼에서 가져오려고 할때 데이터가 버퍼에 존재하지 않은 문제가 있었습니다. 즉 데이터를 버퍼에서 가져오는 액션을 디스패치할시 항상 데이터가 버퍼에 있으라는 보장이 없었던것입니다. 이러한 pull 방식은 불필요할수도 있는 pop 액션을 디스패치하는 문제가 있었습니다.

이러한 문제를 해결하기 위해 redux saga 의 channel 을 도입하였습니다

Redux saga Channel

Redux saga 는 여러 effects 가 존재합니다.

그중에서 saga 의 채널을 이용하여 push 방식의 이벤트 핸들링을 효과적인 pull 방식으로 바꾸었습니다.

channel

redux saga channel의 이해를 돕기 위해 비유를 통해 설명해 보겠습니다. 비유가 들어가서 개념의 약간의 차이가 있을수 있으니 자세한 개념은
redux saga 공식 문서 참고해주시기 바랍니다.

굉장히 장사가 잘되는 중국집이 있다고 해보겠습니다. 장사가 잘되지만 요리사 혼자서 중국집을 운영하고 있어서 손님은 직접 짜장면을 받아가야 합니다. 이 중국집은 두가지의 문제점이 있습니다.
1. 손님은 짜장면의 요리 완료를 지속적으로 체크해야합니다.
2. 제일 먼저 온 손님이 짜장면을 받아야 하는데 순서가 보장되지 않습니다.

중국집은 문제점을 깨닫고 서빙하는 사람을 고용하였습니다.
서빙을 하는 사람은 하는 일이 굉장히 단순합니다. 요리가 완료된 짜장면을 받아다가 짜장면이 나왔다고 간판에 표시해줍니다. 그러면 손님은 순서대로 짜장면을 받아갑니다. 만약 손님들보다 짜장면이 일찍 나오게 되면 짜장면을 쟁반에 잘 놓아둡니다. 그러면 손님들은 짜장면을 순서대로 가져갑니다.

여기에서 서빙을 하는 사람이 redux saga 의 채널입니다. redux saga 의 채널은 버퍼라는 공간에 데이터를 담아두어서 데이터를 소비하는 곳은 버퍼에 데이터가 있을때에만 데이터를 가져가기 때문에 항상 데이터가 있다고 보장이 됩니다 또한 데이터의 순서를 보장하는 역할도 합니다..

redux saga 의 event channel은 외부에서 들어오는 이벤트들은 채널의 버퍼에 담고 테이크로 버퍼(큐)에 있는 이벤트를 가져와서 처리할수 있습니다. 외부작업의 이벤트들을 동기적으로 push된 순서대로 처리할수 있게 된것입니다. 픽앤고 프로젝트에서 웹 소켓은 redux saga 의 event channel 로 처리하였습니다. 외부 이벤트인 웹소켓을 event channel로 연결을 하는것이죠.

channel 에서는 버퍼에 데이터가 담겨있을시에 take 가 이루어지기 때문에 버퍼에 데이터유무를 따로 체크할필요 없이 항상 데이터는 담겨있다고 보장이 됩니다.

redux saga 의 channel 에서도 matcher (데이터 필터링), buffer size 및 buffer overflow 시 어떻게 handling 할지도 지정할수 있습니다. channel 의 다양한 옵션을 사용하여 socket handling 을 더 최적화 할수 있을것 같습니다.

Reference
https://redux-saga.js.org/docs/advanced/Channels/
https://meetup.toast.com/posts/145

profile
arenacast team blog

0개의 댓글