Seneca란?

세네카란 마이크로서비스를 구축하기 위해 작성된 프레임워크이다. 코드에서 전송을 추상화하는 정교한 패턴 매칭 인터페이스를 마이크로서비스에 연결된다. 따라서 세네카를 이용하면 확장성이 높은 아키텍쳐를 쉽게 구축할 수 있다.

install

npm install -g seneca

패턴매칭

seneca.add 를 통해 패턴을 세네카에 패턴이 집합으로 새로운 함수를 추가한다.seneca.act 를 통해 전송된 패턴과 일치하는 서비스에 의해 명령을 실행될 세네카로 전송한다.

var seneca = require('seneca')();
 
seneca.add({role: 'math', cmd: 'sum'}, function(msg, respond) {
  var sum = Number(msg.left) + Number(msg.right);
  respond(null, {answer: sum});
});
 
seneca.add({role: 'math', cmd: 'product'}, function(msg, respond) {
  var product = msg.left * msg.right;
  respond(null, {answer: product});
});
 
// {answer: 3}
seneca.act({role: 'math', cmd: 'sum', left: 1, right: 2}, console.log);
 
// {answer: 12}
seneca.act({role: 'math', cmd: 'product', left: 3, right: 4}, console.log);

패턴 재사용

등록한 패턴을 다음과 같이 재사용할 수 있다.

seneca.add({role: 'math', cmd: 'sum'}, function(msg, respond) {
  var sum = msg.left + msg.right;
  respond(null, {answer: sum});
});
 
seneca.add({role: 'math'}, function(msg, respond) {
  this.act({
    role: 'math',
    cmd: 'sum',
    left: msg.left,
    right: msg.right
  }, respond);
});
 
//{answer: 7}
seneca.act({role: 'math', left: 3, right: 4}, console.log);

매턴 매칭은 어떻게 동작하는가?

매칭된 가장 긴 체인이 적합한 패턴이 된다.

{x:1}과 {x:1, y:2}가 패턴으로 등록되어있다고 가정해보자.

  • {x:1} 요청 -> {x:1}가 가장 적합

  • {x:1, y:2} 요청 -> {x:1, y:2}와 적합

  • {x:1, y:2, z:3} 요청 -> {x:1, y:2}와 적합

  • {y:2} -> 매칭된 패턴 없음.(앞에서부터 매칭 필요)

플러그인

아래와 같이 세네카 외부 함수를 만들고 use를 통해 세네카에 적용시켜 사용할 수 있다.

//math.js
 
function math(name) {
  var name = name;
 
  this.add('role:math, cmd:sum', function(msg, respond) {
    respond(null, {name: Number(msg.left) + Number(msg.right)});
  });
 
  this.add('role:math, cmd:product', function(msg, respond) {
    respond(null, {name: msg.left * msg.right});
  });
}
 
//{bbo: 3}
require('seneca')()
  .use(math, 'bbo')
  .act('role:math, cmd:sum, left:1, right:2', console.log);

마이크로서비스 작성 예시

module.exports = function math(options) {
 
  this.add('role:math,cmd:sum', function sum(msg, respond) {
    respond(null, { answer: Number(msg.left) + Number(msg.right) });
  });
 
  this.add('role:math,cmd:product', function product(msg, respond) {
    respond(null, { answer: msg.left * msg.right });
  });
 
  this.wrap('role:math', function (msg, respond) {
    msg.left  = Number(msg.left).valueOf();
    msg.right = Number(msg.right).valueOf();
    this.prior(msg, respond);
  });
};

위의 코드에서 주의깊게 봐야할 2개의 함수가 있다.

  • seneca.wrap 함수는 패턴과 매칭된 집합들을 같은 action으로 묶는다.

  • seneca.prior 함수는 이전의 정의된 action 을 호출한다. wrap을 통해 확장된 action을 호출후 내부에서 패턴과 일치하는 이전 action을 호출!!

require('seneca')()
  .use('math')
  .act('role:math, cmd:sum, left:3, right:4', console.log);
 
require('seneca')()
  .use('math')
  .act('role:math, cmd:product, left:3, right:4', console.log);

서버 실행 - listen()

require('seneca')()
  .use(math)
  .listen({type: 'tcp', pin: 'role:math'});

curl을 이용하여 패턴과 함께 url을 실행시킨다.(url/act)

$ curl -d '{"role":"math", "cmd":"sum", "left":1, "right":2}' http://localhost:3000/act

클라이언트 접속 - client()

require('seneca')()
// 로컬에 패턴 추가
.add('say:hello', function(msg, respond) {
  respond(null, {text: "Hi!"});
})
// 서버의 listen 매칭과 일치해야 한다.
// 위의 listen() 시 pin: 'role:math'로 하였으므로
// client() 에도 pin: 'role:math'가 되어야 한다.
.client({type: 'tcp', pin: 'role:math'})
// math 모듈의 패턴과 매칭
.act('role:math, cmd:sum, left:1, right:2',console.log)
// 로컬의 패턴과 매칭
.act('say:hello', console.log)
.act('role:math, cmd:product, left:3, right:3', console.log);

출력은 다음과 같을 것이다.

{text: 'hello'}
{answer: 3}
{answer: 9}

역시 비동기로 출력이 됨을 알 수가 있다.

마치며..

마이크로 서비스를 작성하기 앞서 세네카라는 프레임워크에 대해서 조사를 해보았다. 세네카를 사용하면 모듈단위로 확장할 때 패턴 매칭을 이용하기 때문에 확장성과 테스트 단위가 쉬울 것 같다. 다음 시간에는 express와 세네카를 적용해보아야겠다.

'Framework > Nodejs' 카테고리의 다른 글

pm2에 대해 알아보자  (0) 2017.10.06
[마이크로서비스] 세네카와 익스프레스 연동  (0) 2017.10.02
비동기와 CPU Bound  (0) 2017.09.04
node js, mongodb 연동 with mongoose  (0) 2017.08.16
이메일 발송  (0) 2017.07.13

+ Recent posts