Une boîte à outils Node.js pour les architectures de microservices
Ce module open source est sponsorisé et soutenu par Voxgig. |
---|
Seneca est une boîte à outils permettant d'écrire des microservices et d'organiser la logique métier de votre application. Vous pouvez diviser votre application en « choses qui se produisent », plutôt que de vous concentrer sur les modèles de données ou sur la gestion des dépendances.
Sénèque fournit,
correspondance de modèles : une manière merveilleusement flexible de répondre aux exigences de l'entreprise
indépendance du transport : la manière dont les messages parviennent au bon serveur n'est pas quelque chose dont vous devriez vous soucier
maturité : 8 ans en production (avant on l'appelait microservices ), mais a été une fois retiré par la foudre
le plus : un écosystème de plugins profond et large
livre : un guide pour la conception d'architectures de microservices : taomicro
Utilisez ce module pour définir des commandes qui fonctionnent en intégrant du JSON et, éventuellement, en renvoyant du JSON. La commande à exécuter est sélectionnée par correspondance de modèle sur le JSON d'entrée. Il existe des ensembles de commandes intégrés et facultatifs qui vous aident à créer des produits minimum viables : stockage de données, gestion des utilisateurs, logique distribuée, mise en cache, journalisation, etc. Et vous pouvez définir votre propre produit en le divisant en un ensemble de commandes - " des trucs qui arrivent". C'est à peu près tout.
Si vous utilisez ce module et avez besoin d'aide, vous pouvez :
Si vous êtes nouveau sur Seneca en général, veuillez jeter un œil à senecajs.org. Nous avons tout, des didacticiels aux exemples d'applications, pour vous aider à être opérationnel rapidement.
La source de Sénèque peut être lue de manière annotée en exécutant npm run annotate
. Une version annotée de chaque fichier sera générée dans ./docs/
.
Pour installer via 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' }
Pour fonctionner normalement, disons dans un conteneur, utilisez
$ node microservice.js
(où microservice.js
est un fichier de script qui utilise Seneca). Les journaux sont générés au format JSON afin que vous puissiez les envoyer à un service de journalisation.
Pour exécuter en mode test, avec des journaux de débogage complets et lisibles par l'homme, utilisez :
$ node microservice.js --seneca.test
Pour que ça n'ait pas d'importance,
Tant qu'une commande peut gérer un document JSON donné, tout va bien.
Voici un exemple :
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 )
} )
Dans ce code, chaque fois que Seneca voit le modèle {cmd:'salestax'}
, il exécute la fonction associée à ce modèle, qui calcule la taxe de vente. Il n'y a rien de spécial dans la propriété cmd
. C'est simplement la propriété à laquelle nous voulons faire correspondre un modèle. Vous pourriez chercher foo
pour tous les soucis de Sénèque ! Ouais!
La méthode seneca.add
ajoute un nouveau modèle et la fonction à exécuter chaque fois que ce modèle se produit.
La méthode seneca.act
accepte un objet et exécute la commande, le cas échéant, qui correspond.
D'où vient le taux de taxe de vente ? Essayons à nouveau :
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 )
} )
La commande config
vous fournit votre configuration. C'est cool car peu importe d'où provient la configuration - codée en dur, système de fichiers, base de données, service réseau, peu importe. Avez-vous dû définir une API d'abstraction pour que cela fonctionne ? Non.
Il y a un peu mais trop de verbosité ici, vous ne trouvez pas ? Réparons cela :
seneca . act ( 'cmd:salestax,net:100' , function ( err , result ) {
console . log ( result . total )
} )
Au lieu de fournir un objet, vous pouvez fournir une chaîne en utilisant une forme abrégée de JSON. En fait, vous pouvez fournir les deux :
seneca . act ( 'cmd:salestax' , { net : 100 } , function ( err , result ) {
console . log ( result . total )
} )
C'est une manière très pratique de combiner un motif et des données de paramètres .
La façon de créer des systèmes Node.js consiste à créer de nombreux petits processus. Voici un excellent exposé expliquant pourquoi vous devriez faire cela : Programmer Anarchy.
Sénèque rend cela vraiment facile. Mettons la configuration sur le réseau dans son propre processus :
seneca . add ( { cmd : 'config' } , function ( msg , done ) {
var config = { rate : 0.23 }
var value = config [ msg . prop ]
done ( null , { value : value } )
} )
seneca . listen ( )
La méthode listen
démarre un serveur Web qui écoute les messages JSON. Lorsque ceux-ci arrivent, ils sont soumis à l'instance locale de Seneca et exécutés comme des actions de la manière normale. Le résultat est ensuite renvoyé au client en réponse à la requête HTTP. Seneca peut également écouter les actions via un bus de messages.
Votre implémentation du code de configuration reste la même .
Le code client ressemble à ceci :
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 )
} )
Côté client, appeler seneca.client()
signifie que Seneca enverra toutes les actions auxquelles il ne peut pas correspondre localement sur le réseau. Dans ce cas, le serveur de configuration correspondra au modèle cmd:config
et renverra les données de configuration.
Encore une fois, notez que votre code de taxe de vente ne change pas . Il n’a pas besoin de savoir d’où vient la configuration, qui la fournit ou comment.
Vous pouvez le faire avec chaque commande.
Le problème avec les exigences des entreprises, c’est qu’elles n’ont aucun respect pour le bon sens, la logique ou la structure ordonnée. Le monde réel est compliqué.
Dans notre exemple, disons que certains pays ont un taux de taxe de vente unique et que d'autres ont un taux variable, qui dépend soit de la localité, soit de la catégorie de produit.
Voici le code. Nous allons extraire le code de configuration pour cet exemple.
// 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 )
} )
Dans ce cas, vous fournissez différentes implémentations pour différents modèles. Cela vous permet d'isoler la complexité dans des endroits bien définis. Cela signifie également que vous pouvez gérer très facilement des cas particuliers.
L'organisation Senecajs encourage la participation. Si vous pensez pouvoir aider de quelque manière que ce soit, que ce soit avec des rapports de bugs, de la documentation, des exemples, des tests supplémentaires ou de nouvelles fonctionnalités, n'hésitez pas à créer un problème, ou mieux encore, à soumettre une Pull Request. Pour plus d’informations sur la contribution, veuillez consulter notre guide de contribution.
Pour exécuter des tests localement,
npm run test
Pour obtenir un rapport de couverture,
npm run coverage; open docs/coverage.html
Copyright (c) 2010-2018 Richard Rodger et autres contributeurs ; Licence sous MIT .