ชุดเครื่องมือ Node.js สำหรับสถาปัตยกรรม Microservice
โมดูลโอเพ่นซอร์สนี้ได้รับการสนับสนุนและสนับสนุนโดย Voxgig |
---|
Seneca เป็นชุดเครื่องมือสำหรับเขียนไมโครเซอร์วิสและจัดระเบียบตรรกะทางธุรกิจของแอปของคุณ คุณสามารถแบ่งแอปของคุณออกเป็น "สิ่งที่เกิดขึ้น" แทนที่จะมุ่งเน้นไปที่โมเดลข้อมูลหรือจัดการการขึ้นต่อกัน
เซเนกาจัดให้
การจับคู่รูปแบบ: วิธีที่ยืดหยุ่นอย่างน่าอัศจรรย์ในการจัดการกับความต้องการทางธุรกิจ
ความเป็นอิสระในการขนส่ง: วิธีที่ข้อความไปยังเซิร์ฟเวอร์ที่ถูกต้องไม่ใช่สิ่งที่คุณควรกังวล
อายุครบกำหนด: 8 ปีในการผลิต (ก่อนที่เราจะเรียกมันว่า ไมโครเซอร์วิส ) แต่ครั้งหนึ่งเคยถูกฟ้าผ่าออกไป
บวก: ระบบนิเวศของปลั๊กอินที่ลึกและกว้าง
หนังสือ: คู่มือการออกแบบสถาปัตยกรรมไมโครเซอร์วิส: taomicro
ใช้โมดูลนี้เพื่อกำหนดคำสั่งที่ทำงานโดยรับ JSON บางส่วน และอาจส่งคืน JSON บางส่วนหรือไม่ก็ได้ คำสั่งที่จะเรียกใช้จะถูกเลือกโดยการจับคู่รูปแบบบนอินพุต JSON มีชุดคำสั่งในตัวและเป็นทางเลือกที่ช่วยคุณสร้างผลิตภัณฑ์ที่ใช้งานได้ขั้นต่ำ: การจัดเก็บข้อมูล การจัดการผู้ใช้ ลอจิกแบบกระจาย แคช การบันทึก ฯลฯ และคุณสามารถกำหนดผลิตภัณฑ์ของคุณเองโดยแบ่งออกเป็นชุดคำสั่ง - " สิ่งที่เกิดขึ้น". นั่นก็ค่อนข้างมาก
หากคุณกำลังใช้โมดูลนี้และต้องการความช่วยเหลือ คุณสามารถ:
หากคุณยังใหม่กับ Seneca โดยทั่วไป โปรดดูที่ senecajs.org เรามีทุกอย่างตั้งแต่บทช่วยสอนไปจนถึงแอปตัวอย่างเพื่อช่วยให้คุณพร้อมใช้งานได้อย่างรวดเร็ว
แหล่งที่มาของ Seneca สามารถอ่านได้ในรูปแบบคำอธิบายประกอบโดยการรัน npm run annotate
เวอร์ชันที่มีคำอธิบายประกอบของแต่ละไฟล์จะถูกสร้างขึ้นใน ./docs/
/
หากต้องการติดตั้งผ่าน npm
npm install seneca
'use strict'
var Seneca = require ( 'seneca' )
// Functionality in seneca is composed into simple
// plugins that can be loaded into seneca instances.
function rejector ( ) {
this . add ( 'cmd:run' , ( msg , done ) => {
return done ( null , { tag : 'rejector' } )
} )
}
function approver ( ) {
this . add ( 'cmd:run' , ( msg , done ) => {
return done ( null , { tag : 'approver' } )
} )
}
function local ( ) {
this . add ( 'cmd:run' , function ( msg , done ) {
this . prior ( msg , ( err , reply ) => {
return done ( null , { tag : reply ? reply . tag : 'local' } )
} )
} )
}
// Services can listen for messages using a variety of
// transports. In process and http are included by default.
Seneca ( )
. use ( approver )
. listen ( { type : 'http' , port : '8260' , pin : 'cmd:*' } )
Seneca ( )
. use ( rejector )
. listen ( 8270 )
// Load order is important, messages can be routed
// to other services or handled locally. Pins are
// basically filters over messages
function handler ( err , reply ) {
console . log ( err , reply )
}
Seneca ( )
. use ( local )
. act ( 'cmd:run' , handler )
Seneca ( )
. client ( { port : 8270 , pin : 'cmd:run' } )
. client ( { port : 8260 , pin : 'cmd:run' } )
. use ( local )
. act ( 'cmd:run' , handler )
Seneca ( )
. client ( { port : 8260 , pin : 'cmd:run' } )
. client ( { port : 8270 , pin : 'cmd:run' } )
. use ( local )
. act ( 'cmd:run' , handler )
// Output
// null { tag: 'local' }
// null { tag: 'approver' }
// null { tag: 'rejector' }
หากต้องการให้ทำงานได้ตามปกติ เช่น ในภาชนะ ให้ใช้
$ node microservice.js
(โดยที่ microservice.js
เป็นไฟล์สคริปต์ที่ใช้ Seneca) บันทึกจะส่งออกในรูปแบบ JSON ดังนั้นคุณจึงสามารถส่งไปยังบริการบันทึกได้
หากต้องการทำงานในโหมดทดสอบโดยใช้บันทึกการแก้ไขข้อบกพร่องแบบเต็มที่มนุษย์อ่านได้ ให้ใช้:
$ node microservice.js --seneca.test
เพื่อที่จะไม่สำคัญว่า
ตราบใดที่คำสั่ง บาง คำสั่งสามารถจัดการเอกสาร JSON ที่กำหนดได้ คุณก็ทำได้ดี
นี่คือตัวอย่าง:
var seneca = require ( 'seneca' ) ( )
seneca . add ( { cmd : 'salestax' } , function ( msg , done ) {
var rate = 0.23
var total = msg . net * ( 1 + rate )
done ( null , { total : total } )
} )
seneca . act ( { cmd : 'salestax' , net : 100 } , function ( err , result ) {
console . log ( result . total )
} )
ในโค้ดนี้ เมื่อใดก็ตามที่ seneca เห็นรูปแบบ {cmd:'salestax'}
ก็จะเรียกใช้ฟังก์ชันที่เกี่ยวข้องกับรูปแบบนี้ ซึ่งจะคำนวณภาษีการขาย cmd
ไม่มีอะไรพิเศษเกี่ยวกับคุณสมบัตินี้ มันเป็นเพียงคุณสมบัติที่เราต้องการจับคู่รูปแบบ คุณสามารถมองหา foo
สำหรับการดูแลเซเนกาทั้งหมดได้! เย้!
เมธอด seneca.add
จะเพิ่มรูปแบบใหม่และฟังก์ชันที่จะดำเนินการเมื่อใดก็ตามที่รูปแบบนั้นเกิดขึ้น
เมธอด seneca.act
ยอมรับอ็อบเจ็กต์ และรันคำสั่ง (ถ้ามี) ที่ตรงกัน
อัตราภาษีขายมาจากไหน? ลองอีกครั้ง:
seneca . add ( { cmd : 'config' } , function ( msg , done ) {
var config = { rate : 0.23 }
var value = config [ msg . prop ]
done ( null , { value : value } )
} )
seneca . add ( { cmd : 'salestax' } , function ( msg , done ) {
seneca . act ( { cmd : 'config' , prop : 'rate' } , function ( err , result ) {
var rate = parseFloat ( result . value )
var total = msg . net * ( 1 + rate )
done ( null , { total : total } )
} )
} )
seneca . act ( { cmd : 'salestax' , net : 100 } , function ( err , result ) {
console . log ( result . total )
} )
คำสั่ง config
จะให้การกำหนดค่าของคุณ ซึ่งถือว่าเยี่ยมมากเพราะไม่สำคัญว่าจะได้รับการกำหนดค่าจาก ที่ใด ไม่ว่าจะเป็นฮาร์ดโค้ด ระบบไฟล์ ฐานข้อมูล บริการเครือข่าย หรืออะไรก็ตาม คุณต้องกำหนด abstraction API เพื่อให้ใช้งานได้หรือไม่ ไม่.
มีคำฟุ่มเฟือยเล็กน้อยแต่มากเกินไปที่นี่คุณว่าไหม? มาแก้ไขกัน:
seneca . act ( 'cmd:salestax,net:100' , function ( err , result ) {
console . log ( result . total )
} )
แทนที่จะจัดเตรียมออบเจ็กต์ คุณสามารถจัดเตรียมสตริงโดยใช้รูปแบบย่อของ JSON ได้ ที่จริงแล้ว คุณสามารถระบุได้ทั้ง:
seneca . act ( 'cmd:salestax' , { net : 100 } , function ( err , result ) {
console . log ( result . total )
} )
นี่เป็น วิธีที่สะดวกมากในการรวมข้อมูลรูปแบบและพารามิเตอร์
วิธีสร้างระบบ Node.js คือการสร้างกระบวนการเล็กๆ น้อยๆ มากมาย นี่เป็นการพูดคุยที่ดีที่จะอธิบายว่าทำไมคุณควรทำเช่นนี้: Programmer Anarchy
เซเนกาทำให้เรื่องนี้ง่ายมาก มานำการกำหนดค่าบนเครือข่ายเข้าสู่กระบวนการของตัวเอง:
seneca . add ( { cmd : 'config' } , function ( msg , done ) {
var config = { rate : 0.23 }
var value = config [ msg . prop ]
done ( null , { value : value } )
} )
seneca . listen ( )
วิธี listen
จะเริ่มต้นเว็บเซิร์ฟเวอร์ที่รอรับข้อความ JSON เมื่อสิ่งเหล่านี้มาถึง พวกมันจะถูกส่งไปยังอินสแตนซ์ Seneca ในพื้นที่ และดำเนินการตามการดำเนินการตามปกติ ผลลัพธ์จะถูกส่งกลับไปยังไคลเอนต์เป็นการตอบสนองต่อคำขอ HTTP เซเนกายังสามารถฟังการดำเนินการผ่านบัสข้อความได้
การใช้รหัสการกำหนดค่าของคุณ ยังคงเหมือนเดิม
รหัสลูกค้ามีลักษณะดังนี้:
seneca . add ( { cmd : 'salestax' } , function ( msg , done ) {
seneca . act ( { cmd : 'config' , prop : 'rate' } , function ( err , result ) {
var rate = parseFloat ( result . value )
var total = msg . net * ( 1 + rate )
done ( null , { total : total } )
} )
} )
seneca . client ( )
seneca . act ( 'cmd:salestax,net:100' , function ( err , result ) {
console . log ( result . total )
} )
ในฝั่งไคลเอ็นต์ การเรียก seneca.client()
หมายความว่า Seneca จะส่งการดำเนินการใดๆ ที่ไม่สามารถจับคู่ในเครื่องผ่านเครือข่ายได้ ในกรณีนี้ เซิร์ฟเวอร์การกำหนดค่าจะตรงกับรูปแบบ cmd:config
และส่งคืนข้อมูลการกำหนดค่า
โปรดสังเกตอีกครั้งว่ารหัสภาษีการขายของคุณ ไม่มีการเปลี่ยนแปลง ไม่จำเป็นต้องรู้ว่าการกำหนดค่ามาจากไหน ใครเป็นผู้จัดเตรียม หรืออย่างไร
คุณสามารถทำได้ด้วยทุกคำสั่ง
สิ่งที่เกี่ยวกับข้อกำหนดทางธุรกิจก็คือ พวกเขาไม่เคารพสามัญสำนึก ตรรกะ หรือโครงสร้างที่เป็นระเบียบ โลกแห่งความจริงมันวุ่นวาย
ในตัวอย่างของเรา สมมติว่าบางประเทศมีอัตราภาษีขายเดียว และบางประเทศมีอัตราผันแปร ซึ่งขึ้นอยู่กับท้องถิ่นหรือหมวดหมู่ผลิตภัณฑ์
นี่คือรหัส เราจะตัดรหัสการกำหนดค่าสำหรับตัวอย่างนี้ออก
// fixed rate
seneca . add ( { cmd : 'salestax' } , function ( msg , done ) {
var rate = 0.23
var total = msg . net * ( 1 + rate )
done ( null , { total : total } )
} )
// local rates
seneca . add ( { cmd : 'salestax' , country : 'US' } , function ( msg , done ) {
var state = {
'NY' : 0.04 ,
'CA' : 0.0625
// ...
}
var rate = state [ msg . state ]
var total = msg . net * ( 1 + rate )
done ( null , { total : total } )
} )
// categories
seneca . add ( { cmd : 'salestax' , country : 'IE' } , function ( msg , done ) {
var category = {
'top' : 0.23 ,
'reduced' : 0.135
// ...
}
var rate = category [ msg . category ]
var total = msg . net * ( 1 + rate )
done ( null , { total : total } )
} )
seneca . act ( 'cmd:salestax,net:100,country:DE' , function ( err , result ) {
console . log ( 'DE: ' + result . total )
} )
seneca . act ( 'cmd:salestax,net:100,country:US,state:NY' , function ( err , result ) {
console . log ( 'US,NY: ' + result . total )
} )
seneca . act ( 'cmd:salestax,net:100,country:IE,category:reduced' , function ( err , result ) {
console . log ( 'IE: ' + result . total )
} )
ในกรณีนี้ คุณจะจัดเตรียมการใช้งานที่แตกต่างกันสำหรับรูปแบบที่แตกต่างกัน ซึ่งช่วยให้คุณแยกความซับซ้อนออกเป็นตำแหน่งที่กำหนดไว้อย่างชัดเจน นอกจากนี้ยังหมายความว่าคุณสามารถจัดการกับกรณีพิเศษได้อย่างง่ายดาย
องค์กร Senecajs สนับสนุนการมีส่วนร่วม หากคุณรู้สึกว่าสามารถช่วยได้ในทางใดทางหนึ่ง ไม่ว่าจะเป็นการรายงานจุดบกพร่อง เอกสารประกอบ ตัวอย่าง การทดสอบเพิ่มเติม หรือคุณสมบัติใหม่ อย่าลังเลที่จะสร้างปัญหา หรือดีกว่านั้น ให้ส่งคำขอดึงข้อมูล สำหรับข้อมูลเพิ่มเติมเกี่ยวกับการบริจาค โปรดดูคู่มือการบริจาคของเรา
หากต้องการดำเนินการทดสอบในเครื่อง
npm run test
หากต้องการรับรายงานความคุ้มครอง
npm run coverage; open docs/coverage.html
ลิขสิทธิ์ (c) 2010-2018 Richard Rodger และผู้มีส่วนร่วมอื่นๆ; ได้รับอนุญาตภายใต้ MIT