레이블이 node인 게시물을 표시합니다. 모든 게시물 표시
레이블이 node인 게시물을 표시합니다. 모든 게시물 표시

2015년 3월 10일 화요일

node passport session recreate error

node passport session recreate error

when client(ex ios) send 2 request as parallels
1 request is logout
2 request is unregist push notification
2 requests have user logined cookie
so when that requests arrive at node server
passport always do upsert at user session
but if requests processed as below sequence it can make recreate session error

  1. logout request do upsert by passport because request has user session info
    and it returned
  2. logout
    remove session sended at DB
    and it queueed at node asycle cycle
  3. DB delete user session
  4. unregist push notification request do upsert by passport because request has user session info
    DB recreate user session
  5. logout response returned with success
  6. unregist push notification response returned with success
both request success in client
so client think logout success
but in db user session recreated with login status

2015년 2월 4일 수요일

노드에서 env 설정하기

노드에서 env 설정하기


실제 노드로 개발을 하게 되면 보통
server mode 를 만들게 되는대
  • production
  • production_test
  • test
  • dev
등으로 config를 잡게된다.
쉘스크립트에 넣어 쓰거나 쉘변수로 지정해
사용하는대 필요할 경우
아래와 같은 방법으로 줄수 있다
NODE_ENV=production node server.js

2015년 2월 2일 월요일

node 비동기 while 방식 control flow 를 처리

node 비동기 while 방식 control flow 를 처리

개요

node 로 프로그래밍 할경우 가끔 while 방식의 control flow 를 처리해야 하는 경우가 있다
문제는 node 에서는 next()로 밀어 버리기때문에 일반적인 while 방식으로 처리할수 없다는 것이다.
해서 recursive 구조를 사용할 경우 call stack error 때문에 시도 할 수 없는 경우가 많다.
하지만 아래과 같은 방식으로 처리 가능하다.

코드

function isProcessNextJob(callback){
  #db query or some other conditions
  #db.find(function(){
  #  if(spots.length){
  #   return callback(true);
  #  }else{
  #   return callback(false);
  #  }
  #})

  return callback(true);
}

function doRecursiveWork(){
  isProcessNextJob(function(result){
    console.log(result)
    if(result == false){
        return;
    }else{
      setTimeout(doRecursiveWork,0);
    }
  });
}

doRecursiveWork();

한계

물론 위의 문장도 한계가 있다 일단 this 키워드를 사용할수 없으며
call stack 을 새로 만들기 때문에 scope chain 을 사용할수 없다.
하지만 while 방식의 control flow 일 경우 위의 모든것을 감수 하고도 사용 할만한
하나의 대용쯤은 될수 있을 거 같다.

추가내용

settimeout 은 javascript engine 의 event loop 에 새로운 message 를 추가하는 방식으로 작동한다.
*일반적인 함수 호출은 스택위에 싸이는 방식으로 작동

2014년 6월 13일 금요일

node async parallel error 처리시 주의사항

async.parallel([
      function(callback){//1번펑션
         async.parallel([
             function(callback){
                작업1
             },
             function(callback){
                작업2
             }
         ],
         function(err, results){
             
         });
      },
      function(callback){//2번펑션
        async.parallel([
            function(callback){
              작업3
               callback(new Error())
            },
            function(callback){
               작업4
            }
          ],
          function(err, results){

          });
      }
  ],
  function(err, results){
    if(err) res.send(404);
  });

}

페레럴은 동시에 작업을 처리한다.

문제는 아래와 같은 상황에서 발생된다.

1번 펑션은 작업 1까지 처리 되었고
2번 펑션에서 작업 3번후 에러가 발생했을때 이다.

이때 에러가 발생 되었음으로 마지막 펑션을 호출하고 페이지는 리턴된다.

그 후 작업 2가 진행된다.

*즉 에러가 발생 될 경우에 다른 작업이 완료되지 않았어도 마지막 펑션이 호출된다.

그럼 어떻게 사용해야 되는가? 로직에 따라 그냥 에러는 던지지 않고 무조건 널을 리턴하고


async.parallel([
      function(callback){
         callback(null,isSuccess)
      },
      function(callback){
         callback(null,isSuccess)
      }
  ],
  function(err, results){
     if(results 체크){
       res.send(400)
     }
  });

}

callback 함수의 파라미터에 isSuccess 등의 속성을 던져서 마지막 results 부분에서 처리하면 된다

map 등 내부적으로 parallel 을 사용할때는 한번더 생각해보자~

2014년 5월 20일 화요일

node cycle 관련

노드에서 global 영역에 require 를 사용하면 해당 모듈을 init 하는대 필요한 모듈이라고
가정하기 때문에 cycling 을 발생한다.

그렇기 때문에 메서드 안에서 runtime 시 디펜던시가 호출되게 하는 방법이 있다.
(require 는 한번 호출시 캐슁하기때문에 성능 문제는 없다)

1.메서드 안에서 require 사용
//a.js
function a(){

}

a.prototype.onlyAFunction = function(){
  return 'a';
}

a.prototype.withBFunction = function(){
  return require('./b').onlyBFunction();
}

module.exports = new a();

//b.js

function b(){

}

b.prototype.onlyBFunction = function(){
  return 'b';
}

b.prototype.withAFunction = function(){
  return require('./a').onlyAFunction();
}

module.exports  = new b();

//main.js
var a = require('./a');
var b = require('./b');


console.log(a.onlyAFunction());
console.log(a.withBFunction());

console.log(b.onlyBFunction());
console.log(b.withAFunction());

결과
a
b
b
a

2.한쪽에만 의존성이 있을경우 dependency injecttion 을 사용할수 있으나
코드간 의존성이 생기기때문에 개인적으로 비추다..
//a.js
var b = require('./b');

function a(){

}

a.prototype.onlyAFunction = function(){
  return 'a';
}

a.prototype.withBFunction = function(){
  return new b(this).onlyBFunction();
}

module.exports = new a();
//b.js
function b(a){
  this.a = a;
}

b.prototype.onlyBFunction = function(){
  return 'b';
}

module.exports = b;

//main.js
var a = require('./a');
var b = require('./b')(a);


console.log(a.onlyAFunction());
console.log(a.withBFunction());

console.log(b.onlyBFunction());
console.log(b.withAFunction());
3.객체를 생성하지 않고 exports의 property로 사용하는 경우
아래의 경우 객체 생성시 사용되는 의존성이 아니기때문에
(userService, planService 등과 같이 서비스로 사용할시)
가장 깔금하나 모듈 생성시 function(생성자) 를 사용해야 할 경우 문제가 발생함으로 공통코딩 규칙으로 잡기 머하다.


//a.js
console.log('a starting');
exports.done = false;

var b = require('./b4');

exports.onlyAFunction = function(){
  return 'a';
}

exports.withBFunction = function(){
  return b.onlyBFunction();
}

console.log('in a, b.done = %j', b.done);
exports.done = true;
console.log('a done');

//b.js

console.log('b starting');
exports.done = false;

var a = require('./a4');

exports.onlyBFunction = function(){
  return 'b';
}

exports.withAFunction = function(){
  return a.onlyAFunction();
}
console.log('in b, a.done = %j', a.done);
exports.done = true;
console.log('b done');

//main.js
console.log('main starting');
var a = require('./a4');
var b = require('./b4');


console.log(a.onlyAFunction());
console.log(a.withBFunction());

console.log(b.onlyBFunction());
console.log(b.withAFunction());

console.log('in main, a.done=%j, b.done=%j', a.done, b.done);

결과
main starting
a starting
b starting
in b, a.done = false
b done
in a, b.done = true
a done
a
b
b
a
in main, a.done=true, b.done=true

5.위에서 언급한 생성자 사용시 발생하는 문제다.
아래 문제는 노드에서 require 싸이클이 발생할 경우
중간에 완성이 들된 object 를 리턴하기 때문에 발생한다.
참조 http://nodejs.org/api/modules.html#modules_cycles



//a.js
console.log('a starting');
exports.done = false;

var b = require('./b5');

function a(){

}

a.prototype.onlyAFunction = function(){
  return 'a';
}

a.prototype.withBFunction = function(){
  return b.onlyBFunction();
}

module.exports = new a();
console.log('in a, b.done = %j', b.done);
exports.done = true;
console.log('a done');

//b.js
console.log('b starting');
exports.done = false;

var a = require('./a5');

function b(){

}

b.prototype.onlyBFunction = function(){
  return 'b';
}

b.prototype.withAFunction = function(){
  return a.onlyAFunction();
}


module.exports = new b();
console.log('in b, a.done = %j', a.done);
exports.done = true;
console.log('b done');

//main.js
console.log('main starting');

var a =  require('./a5');
var b =  require('./b5');

console.log(1);
console.log(a.onlyAFunction());
console.log(2);
console.log(a.withBFunction());
console.log(3);
console.log(b.onlyBFunction());
console.log(4);
console.log(b.withAFunction());
console.log('end');
2
결과
a starting
b starting
in b, a.done = false
b done
in a, b.done = undefined
a done
1
a
2
b
3
b
4

/Users/yeonghuni/workspace/wishbeen/test/test5/b5.js:19
  return a.onlyAFunction();
           ^
TypeError: Object #<Object> has no method 'onlyAFunction'
    at b.withAFunction (/Users/yeonghuni/workspace/wishbeen/test/test5/b5.js:19:12)

4번후 b.withAFunction()을 호출할때 에러가 발생한다.
왜냐하면 최초 a 생성시  b가 필요해서 b를 생성한다.
이때 b에서 다시 a 를 호출하는대 싸이클링이 생성되기 때문에
덜만들어진 a의 객체를 리턴한다. (이때 a.onlyAFunction)이 존재하지 않는다.
그러므로 실재로 코드를 호출하게 되면 런타임시 에러가 발생한다.

이때 정의된 a 가 왜? 런타임에서 에러가 발생하는가?
자바스크립트에서 idetifier resoultion 은 scope chain 을 대상으로 이루어진다.

각각의 함수는 실행시 자신의 execution context 에서 실행되게 되는대 이때 execution context는 activation/variable object + 부모[[scope(chain)]]이다.

(scope chain 은 function 이 정의 될때 자신이 호출되는 function 의 scope 체인(리스트) 속성  맨앞에 activavion/variable object 를 추가하여 만들어진다.)

위의 경우 new b() 를 하게 되면 b의  activavion/variable object  의 a는 생성되다만 object 이다.

b.withAFucntion 을 할경우 b를 호출 한다 이때 b에는 함수가 없음으로 prototype을 뒤지는대 이때 b.prototyp.withAFunction 이 호출된다.

이때 b.prototyp.withAFunction 은 b가 require 될때 생성되었기 때문에 scope 의 a 객체는
정의 되다 만 객체이다.

정의되다만 객체에는 a의 메서드가 없기 때문에 에러가 발생한다.

https://github.com/joyent/node/blob/master/src/node.js#L738

물런 a가 레퍼런스로 넘어갔으니 b가 완성되고 a 가 완성된 후
코드가 호출 되니 a에 메서드가 호출되야 하지 않느냐 라고 물어볼수 있다.

activation/variable object 는 해당 object 의 현재 모습을 copy 해서 저장하기 때문이다.

즉 main에서 b.withAFunction 은 함수 생성 순간에 복사된 a 오브젝트를 지속적으로 참조한다.