LoginSignup
0
1

More than 3 years have passed since last update.

メッセージベースのMicroServiceをNode.js上で簡単につくれるSenecaを試してみた

Posted at

背景

関わっているプロジェクトで触る機会があったので備忘録的にメモ

Senecaとは

Node.js環境でメッセージベースのMicrorServiceを簡単に構築出来るパッケージ。メッセージはJSON形式です。

Senecaの3つの重要な機能

  • Pattern matching: Instead of fragile service discovery, you just let the world know what sort of messages you care about.
  • Transport independence: You can send messages between services in many ways, all hidden from your business logic.
  • Componentisation: Functionality is expressed as a set of plugins which can be composed together as microservices.

パターンマッチング、独立した転送、コンポーネント化ということで、ソースコードに触れながらこれらの恩恵を感じていきます(笑)

Senecaの基本的な使い方


var seneca = require('seneca')()

seneca.add('role:math,cmd:sum', (msg, reply) => {
  reply(null, {answer: (msg.left + msg.right)})
})

seneca.act({role: 'math', cmd: 'sum', left: 1, right: 2}, function (err, result) {
  if (err) return console.error(err)
  console.log(result)
})

参考:http://senecajs.org/getting-started/

サンプルが凄くシンプルで解りやすかった。
seneca.addがアクションの登録、seneca.actがメッセージの送信。

seneca.add


seneca.add('role:math,cmd:sum', (msg, reply) => {
  reply(null, {answer: (msg.left + msg.right)})
})

1つ目のパラメータが処理対処とするメッセージ(JSON形式)のパターン
2つ目のパラメータが実際に処理対象のメッセージが来た時に実行するFunction(アクション)

アクションはmsgとreplyという2つのパラメータを持っていてmsgはメッセージのPlain Object、replyはコールバックでerrorとresponsdのシグネチャを持っています。

seneca.act

seneca.act({role: 'math', cmd: 'sum', left: 1, right: 2}, function (err, result) {
  if (err) return console.error(err)
  console.log(result)
})

1つ目のパラメータがメッセージ
2つ目のパラメータがコールバック

この例だとseneca.addのreply(null, {answer: (msg.left + msg.right)})で指定された情報がfunctin(errr, rersult)に入ってくる。

その他

seneca.prior

var seneca = require('seneca')()

seneca
  .add('role:math,cmd:sum',function (msg, respond) {
      var sum = msg.left + msg.right
      respond(null, { answer: sum })
    })
  .add('role:math,cmd:sum',function (msg, respond) {
      // make an error if msg.left or msg.right is infinite value
      if (!Number.isFinite(msg.left) ||
          !Number.isFinite(msg.right))
      {
        return respond(new Error("Expected left and right to be numbers."))
      }

      this.prior({
        role:  'math',
        cmd:   'sum',
        left:  msg.left,
        right: msg.right,

      }, function (err, result) {
        if (err) return respond(err)

        result.info = msg.left+'+'+msg.right
        respond(null, result)
      })
    })

  .act('role:math,cmd:sum,left:1.5,right:2.5',
        console.log // prints { answer: 4, info: '1.5+2.5' }
     )

priorを利用することで、メッセージに対するアクションの前に特定の処理を実行することができる。

1つ目のパラメータは事前処理を追加したいメッセージ
2つ目のパラメータは事前処理の内容

また、サンプルコードの中では1つ目のaddで追加したアクションに対して2つ目のaddでアクションのオーバーライドを行なっている。

seneca.use


require('seneca')()
  .use(plugin, options)

useを利用することで、パッケージ化したロジックを利用することが出来る。

1つ目のパラメータは定義した関数名かプラグイン名
2つ目のパラメータは関数やプラグインに渡すオブジェクト

index.js
function math(options) {

  this.add('role:math,cmd:sum', function (msg, respond) {
    respond(null, { answer: msg.left + msg.right })
  })

  this.add('role:math,cmd:product', function (msg, respond) {
    respond(null, { answer: msg.left * msg.right })
  })

}

require('seneca')()
  .use(math)
  .act('role:math,cmd:sum,left:1,right:2', console.log)

こちらが、関数名を指定したケース。
useで指定されるパッケージの場合はthissenecaのインスタンスにアクセス出来る。

math.js
module.exports = function math(options) {

  this.add('role:math,cmd:sum', function sum(msg, respond) {
    respond(null, { answer: msg.left + msg.right })
  })

  this.add('role:math,cmd:product', function product(msg, respond) {
    respond(null, { answer: msg.left * msg.right })
  })

}
index.js
// ①ファイルパスを指定するケース
require('seneca')()
  .use(require('./math.js'))
  .act('role:math,cmd:sum,left:1,right:2', console.log)

// ②パッケージ名を指定するケース
require('seneca')()
  .use('math') // finds ./math.js in local folder
  .act('role:math,cmd:sum,left:1,right:2', console.log)

こちらが、パッケージ名を指定したケース。

seneca.wrap

module.exports = function math(options) {

  this.add('role:math,cmd:sum', function sum(msg, respond) {
    respond(null, { answer: msg.left + 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)
  })

}

wrap を利用すると、特定のパターンにマッチしたメッセージのアクションをオーバーライドすることができる。上記ケースの場合はaddされた2つのアクションの事前処理としてmsg.left、msg.rghtを数値に変換している。

1つ目のパラメータは対象とするメッセージのパターン
2つ目のパラメータはオーバーライドする処理内容

For MicroService

math.js
module.exports = function math(options) {

  this.add('role:math,cmd:sum', function sum(msg, respond) {
    respond(null, { answer: msg.left + 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)
  })

}
service.js
require('seneca')()
  .use('math')
  .listen({ type: 'tcp', pin: 'role:math' })
client.js
require('seneca')()
  .client({ type: 'tcp', pin: 'role:math' })
  .act('role:math,cmd:sum,left:1,right:2',console.log)

listen を利用することで、特定のパターンのメッセージをリッスンすることが出来る。便利!typeにはtcpやamqpなどパッケージをインストールすることで様々なタイプのメッセージを指定出来る。

client を利用することで、特定のパターンのメッセージを指定したタイプにメッセージを発信出来る。

ここからは環境に依存するものが多いので、パラメーターの紹介は割愛。
参考:http://senecajs.org/getting-started/

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1