用于微服务架构的 Node.js 工具包
该开源模块由 Voxgig 赞助和支持。 |
---|
Seneca 是一个用于编写微服务和组织应用程序业务逻辑的工具包。您可以将应用程序分解为“发生的事情”,而不是专注于数据模型或管理依赖项。
塞内卡提供,
模式匹配:一种处理业务需求的极其灵活的方式
传输独立性:消息如何到达正确的服务器不是您应该担心的事情
成熟度:生产了8年(之前我们称之为微服务),但曾经被闪电淘汰
加:深入而广泛的插件生态系统
书籍:微服务架构设计指南:taomicro
使用此模块来定义通过接收一些 JSON 并返回一些 JSON 来工作的命令。通过对输入 JSON 进行模式匹配来选择要运行的命令。有内置和可选的命令集可以帮助您构建最小可行产品:数据存储、用户管理、分布式逻辑、缓存、日志记录等。您可以通过将其分解为一组命令来定义您自己的产品 - ”发生的事情”。差不多就这样了。
如果您正在使用此模块并需要帮助,您可以:
如果您对 Seneca 不太熟悉,请访问 senecajs.org。我们拥有从教程到示例应用程序的所有内容,可帮助您快速启动并运行。
可以通过运行npm run annotate
以带注释的方式阅读 Seneca 的源代码。每个文件的带注释版本将在./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
命令为您提供配置。这很酷,因为它从哪里获取配置并不重要——硬编码、文件系统、数据库、网络服务等等。您是否必须定义一个抽象 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 系统的方法是构建许多小进程。这是一个很好的演讲,解释了为什么你应该这样做:程序员无政府状态。
塞内卡使这一切变得非常容易。让我们将网络上的配置放入其自己的进程中:
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 消息的 Web 服务器。当这些到达时,它们被提交到本地 Seneca 实例,并以正常方式作为操作执行。然后结果作为 HTTP 请求的响应返回给客户端。 Seneca 还可以通过消息总线监听操作。
您对配置代码的实现保持不变。
客户端代码如下所示:
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 组织鼓励参与。如果您觉得自己可以以任何方式提供帮助,无论是错误报告、文档、示例、额外测试还是新功能,请随意创建问题,或者更好的是提交 Pull 请求。有关贡献的更多信息,请参阅我们的贡献指南。
要在本地运行测试,
npm run test
要获取覆盖率报告,
npm run coverage; open docs/coverage.html
版权所有 (c) 2010-2018 Richard Rodger 和其他贡献者;获得麻省理工学院许可。