[서버] Node.js Redis Only (P)SUBSCRIBE / (P)UNSUBSCRIBE / PING / QUIT allowed in this context 오류 해결

Coinlist.xyz 페이지를 만들면서 Socket.io를 이용하여 데이터 크롤링 결과를 실시간으로 뿌려주는 기능을 구현하였다.

물론 Node.js를 두개로 나누어 웹 서비스용과 데이터 크롤링 및 전송용으로 나눠서 사용했지만, Node.js http request 모듈이

특정 사이트에 가면 timeout이 생기는 문제가 발생했다.(Node.js가 Non-blocking이 아니었나..)

그래서 서버를 웹 서비스 / 데이터 크롤링 / 데이터 전송 세가지로 나누고, 데이터 크롤링 서버가 데이터를 redis 상에 업데이트 하면

이 정보를 데이터 전송 서버에 전달하도록 구현하는데 redis publish, subscribe를 사용했다.

 

우선 데이터 크롤링에서 얻은 데이터는 실시간 데이터기 때문에 소실되어도 문제가 크게 없어서, redis pub/sub이 적당하였다.

사실 MQ(메시지큐)를 쓰게되면, 오히려 데이터를 체크하고 제거하는게 문제가 될 수도 있었다. (Scale Out을 고려하면 더욱)

 

아무튼 인터넷상에 다양한 예제들을 보면서 대충 구현했는데, 문제가 생겨버렸다.

 

Only (P)SUBSCRIBE / (P)UNSUBSCRIBE / PING / QUIT allowed in this context

오류가 발생했는데, 어제 처음 레디스를 사용해본 것이라 멘탈이 탈탈 털려버렸다.

저 오류는 subscribe 하고 있는 redis connection이 저 위의 명령 외의 다른 명령(데이터를 가져온다던지, 입력한다던지)을 수행하면, 현재 커넥션은 subscribe중이라 다른 동작은 할 수 없다는 뜻이었는데, 당연히 커넥션 재활용은 하지 않은 상태.

 

일반적으로 인터넷 예제에서는 pub/sub 커넥션 2개와 데이터 관리용 커넥션 1개, 총 3개를 사용한다.

나도 당연히 이를 참조한거기 때문에 커넥션 3개 이상을 사용했다.(디버깅할때는 3개로 해봤지만) 근데 안되네..

 

진짜 별 삽질을 다해봤는데, 이유를 찾을 수 없었다.

두어시간 날려버리고, 우연치 않게 redis-cli에서 커넥션 리스트를 확인하면서 알 수 있었는데…

결론은 커넥션이 2개밖에 안생겼다. 즉 커넥션 생성이 문제가 있었던 것.

 

왜일까… 우선 내 코드는 모듈화를 위해서 따로 redis-client.js를 작성하고 이를 require 명령으로 import후 사용하는 것이다.

redis-client.js

// redis-client.js
var redis = require('redis');
var redisConfig = require('./redis-client-info');
module.exports = (function(){
  var rds = new redis.createClient(redisConfig.port, redisConfig.host);
  return {
    client : rds
  };
}());

sending-server.js

// 기존 코드
// redis-client.js를 바탕으로 새로 만든 모듈들
var rdb = require('./redis-db');
var crdb = reuqire('./redis-db'); 
var rpub = require('./pub-sub.js');
var rsub = require('./pub-sub.js');

pub-sub.js

module.exports = function(){
  var client = require('./util/redis-client').client; 
  function subscribe(channel){
    client.subscribe(channel);
  }
  function publish(channel, data){
    client.publish(channel, data);
  }
  function ping(channel){
    client.ping(channel);
  }
  function onMsgListener(callback){
    client.on("message", function(channel, message){
      callback(channel,message);
    });
  }
  return {
    subscribe:subscribe,
    publish:publish,
    ping:ping,
    client:client,
    onMsgListener:onMsgListener
  };
}();

 

변경한 코드

pub-sub.js

var rutils = require('./util/redis-utils');
var redisConfig = require('./util/redis-client-info');
var redis = require('redis');

module.exports = function(){
 var client = new redis.createClient(redisConfig.port, redisConfig.host);
 function subscribe(channel){
 client.subscribe(channel);
 }
 function publish(channel, data){
 client.publish(channel, data);
 }
 function ping(channel){
 client.ping(channel);
 }
 function onMsgListener(callback){
 client.on("message", function(channel, message){
 callback(channel,message);
 });
 }
 return {
 subscribe:subscribe,
 publish:publish,
 ping:ping,
 client:client,
 onMsgListener:onMsgListener
 };
}();

 

즉, 그냥 pub-sub 소스코드에서 redis의 createClient를 호출했다.

왜 안되던 것이었을까? 심지어 동일한 JS 모듈을 호출하는게 여러개나 있었는데!

정말 이해하지 못하겠다. 그래서 나는 버그라고 자기 위로를 하고있다.

 

혹시 아시는분 있다면 댓글로 알려주세요.

 

jcdgods

누구게?

You may also like...

답글 남기기

이메일은 공개되지 않습니다. 필수 입력창은 * 로 표시되어 있습니다.

Translate »