Comment configurer une architecture de microservices dans Ruby : un guide étape par étape
Publié: 2022-03-11Que sont les microservices ?
Les microservices sont l'une des dernières tendances en matière de conception de logiciels où plusieurs services indépendants communiquent entre eux et disposent de leurs propres processus et ressources. Cette approche diffère d'une conception d'application client-serveur classique. L'application client-serveur habituelle se compose d'un ou plusieurs clients, d'un back-end monolithique qui inclut toutes les données et la logique du domaine, et d'une API qui permet aux clients d'accéder au back-end et à ses fonctionnalités.
Dans une architecture de microservices, le backend monolithique décrit est plutôt remplacé par une suite de services distribués. Cette conception permet une meilleure séparation des responsabilités, une maintenance plus facile, une plus grande flexibilité dans le choix des technologies pour chaque service, une évolutivité et une tolérance aux pannes plus faciles. Dans le même temps, les systèmes distribués complexes ont leur lot de défis. Ils ont plus de chances d'avoir à faire face à des conditions de concurrence, et ils sont plus difficiles à déboguer car les problèmes ne sont pas facilement identifiés à un seul service, mais sont plutôt répartis sur plusieurs. Si un effort n'est pas fait pour suivre les meilleures pratiques lors de la construction d'un tel système, vous pouvez vous retrouver entouré d'incendies que vous ne savez pas comment éteindre. Une attention particulière doit être portée aux contrats de charge utile des services, car les modifications d'un service peuvent affecter tous ses clients, et par conséquent toute la suite de services du back-end.
Toutes ces considérations sont importantes, mais supposons que vous y ayez déjà réfléchi. Maintenant, ce que vous voulez, c'est trouver un moyen de créer vous-même un back-end de microservices. Alors plongeons-y directement.
Comment configurer une architecture de microservices
Il existe actuellement de nombreuses façons de configurer vos microservices, et dans ce guide, nous nous concentrerons sur une architecture de courtier.
Une architecture de courtier
Une architecture de courtier est l'un des moyens par lesquels vous pouvez faire communiquer vos services entre eux. Dans celui-ci, tous les services entourent un serveur de messagerie, le broker, et tous y sont connectés. Les services envoient des messages au courtier, qui sait alors de quel(s) autre(s) service(s) il a besoin pour transmettre ces messages. De cette façon, les services n'ont pas besoin de conserver des informations sur d'autres services. Au lieu de cela, ils comptent sur le courtier pour s'occuper de toute la messagerie, ce qui leur permet d'être isolés et concentrés uniquement sur leur domaine particulier. Un courtier peut également stocker des messages lorsque leurs destinataires sont en panne, ce qui permet aux expéditeurs et aux destinataires de ne pas être forcés d'être actifs simultanément, permettant ainsi une isolation encore plus grande. Bien sûr, cette solution présente des inconvénients car le courtier peut rapidement devenir un goulot d'étranglement puisque toutes les communications doivent passer par lui, et il peut également devenir un point de défaillance unique pour votre backend. Cependant, il existe plusieurs façons d'atténuer ces problèmes. Une façon consiste à avoir plusieurs instances du courtier s'exécutant en parallèle, ce qui permettrait une meilleure tolérance aux pannes du système. Une autre façon serait d'utiliser d'autres architectures. Les architectures alternatives diffèrent de l'architecture que nous allons implémenter dans ce guide en n'utilisant pas de courtier, ou en utilisant une architecture de courtier différente, ou en utilisant un protocole de messagerie différent tel que HTTP.
Communication entre services
Dans ce guide, nous utiliserons ZeroMQ pour gérer la communication entre les services et le courtier.
ZeroMQ fournit une couche d'abstraction de protocole qui gère les messages asynchrones en plusieurs parties sur des transports aléatoires. Les avantages de l'utilisation de ZeroMQ pour la messagerie entre les services et le courtier sortent du cadre de ce guide, nous ne les aborderons donc pas ici, mais si vous voulez en savoir plus à leur sujet, consultez l'article suivant de Quora. Si vous souhaitez découvrir d'autres moyens de faire communiquer vos services, je vous suggère de consulter l'article Broker vs. Brokerless pour voir ce qui peut être réalisé d'autre.
Construire la suite de microservices
Cet article vous guidera à travers toutes les étapes nécessaires à la création de votre suite de microservices. Notre système sera composé d'un courtier et d'un service. Nous utiliserons également un petit script client pour tester les appels à la suite de services, mais gardez à l'esprit que le code client peut facilement être utilisé n'importe où.
Alors, commençons à construire.
Commencer
Tout d'abord, assurons-nous que vous disposez de tout ce dont vous avez besoin pour exécuter le courtier et le service. Tout d'abord, commencez par télécharger et installer Node.js, ZeroMQ et Git sur votre machine. Si vous utilisez OSX, il existe des packages homebrew pour chacun d'eux, et la plupart des distributions Linux ont également un package pour chacun d'eux, vous ne devriez donc pas avoir de problème avec cela. Les utilisateurs de Windows peuvent simplement utiliser les liens de téléchargement fournis ci-dessus.
Exécution du courtier
Après avoir installé toutes les dépendances requises, lançons notre courtier en cours d'exécution. Dans ce guide, nous utilisons une implémentation Node.js du courtier qui fait partie de la suite orientée service ZMQ. Vous pouvez trouver son code et sa documentation sur GitHub. Pour exécuter le broker, clonez d'abord un bootstrap Broker sur votre machine. Ce référentiel est un bootstrap pour utiliser la bibliothèque de courtier ci-dessus. Notez que cette étape n'est pas requise car la bibliothèque d'origine est elle-même exécutable, mais la différence entre les deux est que dans le référentiel d'amorçage, vous pouvez modifier les configurations par défaut.
Donc, tout d'abord, utilisez la commande Git suivante pour télécharger le projet sur votre machine :
$ git clone [email protected]:dadah/zmq-broker-bootstrap.git
Après avoir fait cela, déplacez-vous dans le répertoire créé :
$ cd zmq-broker-bootstrap
Installez maintenant les dépendances du package :
$ npm install
Le courtier est maintenant prêt. Pour exécuter votre courtier, exécutez la commande suivante :
$ bin/zss-broker run
Vous pouvez trouver des fichiers de configuration pour chaque environnement dans le répertoire config/
. Voici la configuration de développement par défaut :
{ "broker": { "backend": "tcp://127.0.0.1:7776", "frontend": "tcp://127.0.0.1:7777" }, "log": { "consolePlugin": { "level": "debug" } } }
Le paramètre backend
définit l'adresse ip:port
du backend et du frontend du courtier. L'adresse principale est l'endroit où le courtier reçoit les demandes et répond aux services, et l'adresse frontale est l'endroit où il reçoit et envoie les clients du service. Vous pouvez également définir le niveau de journalisation en modifiant le log.consolePlugin.level
. Les valeurs possibles sont trace
, debug
, info
, warn
et error
, et elles déterminent la quantité de journalisation que le processus du courtier d'informations produira.
Exécution du service
Une fois que vous avez créé votre courtier, il est temps de développer votre premier microservice Ruby. Commencez par ouvrir une nouvelle fenêtre de console. Ensuite, créez un répertoire dans lequel vos services seront stockés, puis accédez à ce répertoire. Dans ce guide, nous utilisons le client Ruby et le service de ZMQ SOA Suite. Un service d'amorçage "Hello world" est disponible, alors utilisons-le pour lancer notre premier microservice.
Accédez à votre répertoire de services et clonez le dépôt d'amorçage :
$ git clone [email protected]:dadah/zmq-service-suite-ruby-bootstrap.git
Allez dans le répertoire nouvellement créé :
$ cd zmq-service-suite-ruby-bootstrap
Installez maintenant toutes les dépendances :
$ bundle install
Pour démarrer le service, exécutez la commande suivante :
$ bin/zss-service run
Génial. Votre premier service est opérationnel.
Si vous accédez à la fenêtre de la console dans laquelle vous avez laissé votre courtier en cours d'exécution, vous pouvez voir la sortie suivante :
2015-12-15 16:45:05 | INFO | BROKER - Async Broker is waiting for messages... 2015-12-15 16:45:14 | DEBUG | BACKEND - received from: hello-word#aaa65374-8585-410a-a41d-c8a5b024553b rid: 76f50741-913a-43b9-94b0-36d8f7bd75b1 2015-12-15 16:45:14 | DEBUG | BACKEND - routing from: hello-word#aaa65374-8585-410a-a41d-c8a5b024553b rid: 76f50741-913a-43b9-94b0-36d8f7bd75b1 to SMI.UP request... 2015-12-15 16:45:14 | INFO | SMI - SMI register for sid: HELLO-WORD instance: hello-word#aaa65374-8585-410a-a41d-c8a5b024553b! 2015-12-15 16:45:14 | DEBUG | BACKEND - reply to: hello-word#aaa65374-8585-410a-a41d-c8a5b024553b rid: 76f50741-913a-43b9-94b0-36d8f7bd75b1 with status: 200 2015-12-15 16:45:15 | DEBUG | BACKEND - received from: hello-word#aaa65374-8585-410a-a41d-c8a5b024553b rid: 3b3a0416-73fa-4fd2-9306-dad18bc0502a 2015-12-15 16:45:15 | DEBUG | BACKEND - routing from: hello-word#aaa65374-8585-410a-a41d-c8a5b024553b rid: 3b3a0416-73fa-4fd2-9306-dad18bc0502a to SMI.HEARTBEAT request... 2015-12-15 16:45:15 | DEBUG | BACKEND - reply to: hello-word#aaa65374-8585-410a-a41d-c8a5b024553b rid: 3b3a0416-73fa-4fd2-9306-dad18bc0502a with status: 200 2015-12-15 16:45:16 | DEBUG | BACKEND - received from: hello-word#aaa65374-8585-410a-a41d-c8a5b024553b rid: b3044c24-c823-4394-8204-1e872f30e909 2015-12-15 16:45:16 | DEBUG | BACKEND - routing from: hello-word#aaa65374-8585-410a-a41d-c8a5b024553b rid: b3044c24-c823-4394-8204-1e872f30e909 to SMI.HEARTBEAT request... 2015-12-15 16:45:16 | DEBUG | BACKEND - reply to: hello-word#aaa65374-8585-410a-a41d-c8a5b024553b rid: b3044c24-c823-4394-8204-1e872f30e909 with status: 200
Ce journal signifie que le courtier a reconnu l'existence d'un nouveau service et reçoit des messages de pulsation de celui-ci. Chaque seconde, le service envoie un message de pulsation au courtier, afin qu'il sache que l'instance du service est active.
Consommer du Service
Alors maintenant, nous avons un service en cours d'exécution, comment l'utilisons-nous ?
Dans le référentiel d'amorçage, il existe un client factice que vous pouvez utiliser pour tester votre service "Hello World". Ouvrez simplement une nouvelle fenêtre ou un nouvel onglet de console et accédez à votre répertoire de services. Une fois que vous y êtes, lancez la commande suivante :
$ bin/zss-client
Vous devriez voir quelque chose comme ceci :
15-49-15 16:49:54 | INFO | ZSS::CLIENT - Request 90a88081-3485-45b6-91b3-b0609d64592a sent to HELLO-WORD:*#HELLO/WORLD with 1.0s timeout 15-49-15 16:49:54 | INFO | ZSS::CLIENT - Received response to 90a88081-3485-45b6-91b3-b0609d64592a with status 200 "Hello World"
Si vous accédez à la fenêtre de la console où votre service s'exécute, vous devriez voir ceci :
Started hello-word daemon... 15-45-15 16:45:14 | INFO | ZSS::SERVICE - Starting SID: 'HELLO-WORD' ID: 'hello-word#aaa65374-8585-410a-a41d-c8a5b024553b' Env: 'development' Broker: 'tcp://127.0.0.1:7776' 15-49-15 16:49:54 | INFO | ZSS::SERVICE - Handle request for HELLO-WORD:*#HELLO/WORLD 15-49-15 16:49:54 | INFO | ZSS::SERVICE - Reply with status: 200
Bien. Vous venez de lancer et de consommer votre microservice « Hello World ». Ce n'est pourtant pas ce que nous avons entrepris de faire. Nous voulons construire notre (nos) service(s). Allons-y, alors.
Construire votre service
Tout d'abord, arrêtons notre service "Hello World". Accédez à la fenêtre de la console du service et appuyez sur Ctrl+C
pour arrêter le service. Ensuite, nous devons transformer notre service "Hello World" en service "Person".
Structure des codes
Commençons par jeter un œil à l'arbre de code du projet. Il ressemble à ceci :
- Le répertoire
bin
est l'endroit où vous stockez les scripts qui lancent votre service. - Le répertoire
config
stocke tous les fichiers de configuration.- Le fichier
boot.rb
est l'endroit où vous pouvez ajouter toutes vos dépendances de service. Si vous l'ouvrez, vous remarquerez que de nombreuses dépendances y sont déjà répertoriées. Si vous avez besoin d'en ajouter, c'est ici que vous devez le faire. - Le fichier
application.yml
stocke tous les paramètres de votre application. Nous reviendrons sur ce dossier plus tard. - Dans le répertoire
config/initializers
, vous pouvez ajouter vos scripts d'initialisation. Vous pouvez, par exemple, ajouter ici des paramètres pour les connexions ActiveRecord ou Redis. Les scripts que vous ajoutez à ce répertoire s'exécuteront au démarrage du service.
- Le fichier
- Dans le répertoire
db/migrate
, vous pouvez stocker vos migrations ActiveRecord ou Sequel si vous en avez. Si vous ne le faites pas, vous pouvez supprimer complètement ce répertoire. - Le répertoire
lib
est l'endroit où réside votre code d'application principal.- Le fichier
settings.rb
charge simplement le fichierapplication.yml
et le rend disponible dans toute la portée du service, afin que vous puissiez accéder à vos configurations n'importe où. Par exemple,Settings.broker.backend
renvoie l'adresse principale du courtier que vous avez définie dans le fichier YML ci-dessus. - Le fichier
service_register.rb
est l'endroit où vous enregistrez vos services et vos itinéraires de service. Nous l'expliquerons plus tard. - Le fichier
hello_world_service.rb
définit les points de terminaison du service "Hello World". - Le répertoire
lib/daos
est l'endroit où vous stockez vos objets ActiveModel si vous utilisez ActiveRecord, ou tout autre objet d'accès aux données que vous pourriez éventuellement créer, comme vos modèles Sequel. - Le répertoire
lib/dtos
stocke vos objets de transfert de données. Ces objets sont ceux qui sont finalement renvoyés aux clients du service. - Le
lib/repositories
stocke vos référentiels. Les référentiels sont des objets qui permettent aux services d'accéder aux données et sont les seuls objets autorisés à gérer les DAO. Ainsi, si un service souhaite un groupe d'instances "Hello World", il les demandera au référentiel. Le référentiel, à son tour, utilise les DAO appropriés pour extraire les données pertinentes de la base de données. Les données sont ensuite mappées dans une collection DTO « HelloWorld » ou DTO « HelloWorld » appropriée qui est renvoyée au service. - Le
lib/repositories/mappers
est l'endroit où vous stockez vos mappeurs. Les mappeurs sont des objets qui convertissent les DAO en DTO, et vice-versa.
- Le fichier
Le fichier application.yml
du répertoire config
ressemble à ceci :

defaults: &defaults broker: backend: tcp://127.0.0.1:7776 frontend: tcp://127.0.0.1:7777 logging: console: level: info development: <<: *defaults test: <<: *defaults production: <<: *defaults
Ce paramètre définit simplement l'adresse principale et frontale du courtier, ainsi que le niveau de journalisation.
Si tout cela semble déroutant jusqu'à présent, ne vous inquiétez pas car cela deviendra plus clair à mesure que nous avancerons.
Prestation « à la personne »
Alors, continuons avec notre service "Personne". Commençons par configurer la connexion à la base de données. Ouvrez le fichier config/initializers/active_record.rb
et décommentez la seule ligne qui s'y trouve. Ensuite, ajoutez l'entrée suivante à votre configuration de développement dans le application.yml
pour qu'elle ressemble à ceci :
defaults: &defaults broker: backend: tcp://127.0.0.1:7776 frontend: tcp://127.0.0.1:7777 logging: console: level: info database: adapter: postgresql database: zss-tutorial-development
Maintenant que vous avez ajouté votre configuration de base de données, vous devez créer la base de données. Pour le moment, il n'y a aucun moyen de le faire automatiquement à moins que vous n'utilisiez une base de données PostgreSQL par défaut, auquel cas vous pouvez simplement exécuter :
$ rake db:create
Si vous préférez une autre base de données, vous devez ajouter la gemme appropriée au fichier gem, puis installer le projet en bundle.
Vient ensuite la migration. Pour cela, créez simplement le fichier db/migrate
nommé 000_creates_persons.rb
:
$ touch db/migrate/000_creates_persons_table.rb
Ouvrez le fichier et créez la migration comme vous le feriez avec une migration Rails standard :
class CreatesPersons < ActiveRecord::Migration def change create_table :persons do |t| t.name t.timestamps end end end
Ensuite, lancez-le :
$ rake db:migrate == 0 CreatesPersons: migrating ================================================ -- create_table(:persons) DEPRECATION WARNING: `#timestamp` was called without specifying an option for `null`. In Rails 5, this behavior will change to `null: false`. You should manually specify `null: true` to prevent the behavior of your existing migrations from changing. (called from block in change at /Users/francisco/Code/microservices-tutorial/db/migrate/000_creates_persons.rb:6) -> 0.0012s == 0 CreatesPersons: migrated (0.0013s) =======================================
Maintenant que notre table est créée, créons un modèle pour celle-ci. Créez le fichier lib/daos/person.rb
:
$ touch lib/daos/person.rb
Modifiez-le comme ceci :
module DAO class Person < ActiveRecord::Base end end
Il y a votre modèle. Vous devez maintenant créer un modèle DTO pour une "Personne" afin de pouvoir le renvoyer au client. Créez le fichier lib/dtos/person.rb
:
$ touch lib/dtos/person.rb
Modifiez-le comme ceci :
module DTO class Person < Base attr_reader :id, :name end end
Ensuite, vous devez créer un Mapper pour convertir le DAO "Person" en un DTO "Person". Créez le fichier lib/repositories/mappers/person.rb
et éditez-le comme ceci :
module Mapper class Person < Mapper::Base def self.to_dao dto_instance DAO::Person.new id: dto_instance.id, name: dto_instance.name end def self.to_dto dao_instance DTO::Person.new id: dao_instance.id, name: dao_instance.name end end end
Ici, Mapper::Base
vous demande d'implémenter self.to_dao
et self.to_dto
. Si vous ne le souhaitez pas, vous pouvez implémenter self.map
à la place et remplacer le Mapper::Base.map
qui appelle to_dao
ou to_dto
, selon que l'attribut qu'il reçoit est un DAO ou un DTO.
Vous avez maintenant un DAO pour accéder à votre base de données, un DTO pour l'envoyer au client et un Mapper pour convertir l'un dans l'autre. Vous pouvez maintenant utiliser ces trois classes dans un référentiel pour créer la logique qui vous permet d'obtenir des personnes de la base de données et de renvoyer une collection correspondante de DTO.
Créons alors le dépôt. Créez le fichier lib/repositories/person.rb
:
$ touch lib/dtos/person.rb
Modifiez-le comme ceci :
module Repository class Person < Repository::Base def get DAO::Person.all.map do |person| Mapper::Person.map(person) end end end end
Ce référentiel n'a que la méthode d'instance get
qui récupère simplement toutes les personnes de la base de données et les mappe dans une collection de DTO de personnes - assez simple. Réunissons tout cela maintenant. Il ne reste plus qu'à créer le service et le point de terminaison qui appelle ce référentiel. Pour cela, créons le fichier lib/person_service.rb
:
$ touch lib/person_service.rb
Modifiez-le comme ceci :
class PersonService < BaseService attr_reader :person_repo def initialize @person_repo = Repository::Person.new end def get payload, headers persons = person_repo.get() if persons.empty? raise ZSS::Error.new(404, "No people here") else persons.map &:serialize end end end
Le service "Person" initialise le référentiel dans son initialiseur. Toutes les méthodes d'instance publique du service "Person" ont une charge utile et des en-têtes que vous pouvez omettre si vous n'en avez pas besoin. Les deux sont des instances Hashie::Mash
et elles stockent les variables envoyées au point de terminaison, sous forme d'attributs ou d'en-têtes, et leurs réponses imitent les réponses HTTP car chaque réponse a un code d'état que les clients peuvent utiliser pour connaître le résultat des requêtes envoyées au service, ainsi que la charge utile de réponse du service. Les codes de réponse sont les mêmes que ceux que vous attendez d'un serveur HTTP. Par exemple, une demande réussie renverra un code d'état 200, ainsi que la charge utile de la réponse. Si une erreur de service se produit, le code d'état sera 500, et s'il y a un problème avec les paramètres envoyés au serveur, le code d'état sera 400. Le service peut répondre avec la plupart des codes d'état HTTP avec sa charge utile. Ainsi, si, par exemple, vous souhaitez que votre service indique à ses clients qu'ils ne sont pas autorisés à accéder à un certain point de terminaison, vous pouvez le faire en répondant avec un code 403. Vous pouvez voir un autre exemple de codes de réponse si vous regardez notre code de service ci-dessus. Dans le point de terminaison get
, nous renvoyons le code d'état 404 avec le message facultatif "Aucune personne ici" lorsqu'aucune personne n'est trouvée, tout comme un serveur HTTP renverrait un 404 s'il n'y a pas de ressources disponibles. Si le référentiel renvoie effectivement des personnes, le service sérialise les DTO et les renvoie au client. Chaque DTO a un sérialiseur par défaut qui renvoie un objet JSON avec les clés et les valeurs correspondantes définies comme attr_reader
ou attr_accessible
dans la définition DTO. Vous pouvez, bien sûr, remplacer le sérialiseur en définissant votre méthode de sérialisation dans vos classes DTO.
Maintenant que nous avons défini un service, nous devons l'enregistrer. C'est la dernière étape. Ouvrez le fichier lib/service_register.rb
et remplacez toutes les occurrences de "HelloWorld" par "Person", afin que le fichier ressemble finalement un peu à ceci :
module ZSS class ServiceRegister def self.get_service config = Hashie::Mash.new( backend: Settings.broker.backend ) service = ZSS::Service.new(:person, config) personInstance = PersonService.new service.add_route(personInstance, :get) return service end end end
Comme vous l'avez probablement remarqué, il y a un petit changement dans l'appel add_route
. Nous avons supprimé la chaîne "HELLO/WORLD". En effet, la chaîne n'est nécessaire que si le verbe de service ne correspond pas à la méthode qui l'implémente. Dans notre cas, lors de l'appel du service person avec le verbe GET, la méthode à appeler est get
, nous pouvons donc omettre la chaîne.
La classe ServiceRegister
est l'endroit où vous devez définir la méthode self.get_service
. Cette méthode initialise le service et le connecte au backend du broker. Il fait ensuite correspondre les routes de ce service aux méthodes d'une ou plusieurs définitions de service. Par exemple, dans le cas suivant, il crée le service et le lie au courtier :
config = Hashie::Mash.new( backend: Settings.broker.backend ) service = ZSS::Service.new(:person, config)
Ensuite, il instancie un gestionnaire de service :
personInstance = PersonService.new
Ensuite, le gestionnaire de service est lié au service :
service.add_route(personInstance, :get)
Enfin, il doit renvoyer l'instance de service.
return service
Désormais, il ne reste plus qu'une dernière étape avant de pouvoir lancer notre service « Personne » ; nous devons créer un script exécutable pour cela. Nous en avons déjà un pour le "HelloService". Alors, ouvrez le fichier bin/zss-service
, remplacez « hello-word » par « person » et enregistrez le fichier. Revenez à la console et exécutez :
$ bin/zss-service run Starting person: PID: ./log LOGS: ./log Started person daemon... 15-29-15 19:29:54 | INFO | ZSS::SERVICE - Starting SID: 'PERSON' ID: 'person#d3ca7e1f-e229-4502-ac2d-0c01d8c285f8' Env: 'development' Broker: 'tcp://127.0.0.1:7776'
C'est ça. Vous venez de démarrer votre service « Personne » pour la première fois. Maintenant, testons-le. Ouvrez le fichier bin/zss-client
, changez la variable sid
en « person » et changez l'appel client de hello_world()
en get()
. Une fois cela fait, lancez le client dans une nouvelle fenêtre :
$ bin/zss-client /Users/francisco/.rvm/gems/ruby-2.1.2/gems/zss-0.3.4/lib/zss/client.rb:41:in `new': No people here (ZSS::Error) from /Users/francisco/.rvm/gems/ruby-2.1.2/gems/zss-0.3.4/lib/zss/client.rb:41:in `call' from /Users/francisco/.rvm/gems/ruby-2.1.2/gems/zss-0.3.4/lib/zss/client.rb:55:in `method_missing' from bin/zss-client:12:in `<main>'
Comme vous pouvez le voir, vous avez attrapé un ZSS::Error
. En effet, nous générons une erreur lorsqu'aucune personne n'est trouvée par le service et que nous n'avons encore aucune personne dans la base de données de notre service.
Laissez-nous gérer cette erreur alors. Ouvrez zss-client
et éditez-le comme ceci :
begin client = ZSS::Client.new(sid, config) p client.get() rescue ZSS::Client => e if e.code == 404 p e.message else raise e end end
Maintenant, nous imprimons le message d'erreur lorsque le code d'erreur est 404, tout en augmentant l'erreur s'il s'agit d'un code différent. Voyons-le en action en exécutant à nouveau notre client :
$ bin/zss-client "No people here"
Excellent. Ajoutons maintenant quelques personnes à notre table et voyons si elles sont renvoyées par le service à notre client. Pour cela, ouvrez simplement une console de service :
$ rake service:console
Ajoutez quelques personnes :
$ rake service:console [1] pry(main)> DAO::Person.create name: 'John' => #<DAO::Person:0x007fe51bbe9d00 id: 1, name: "John", created_at: 2015-12-16 13:22:37 UTC, updated_at: 2015-12-16 13:22:37 UTC> [2] pry(main)> DAO::Person.create name: 'Mary' => #<DAO::Person:0x007fe51c1dafe8 id: 2, name: "Mary", created_at: 2015-12-16 13:22:42 UTC, updated_at: 2015-12-16 13:22:42 UTC> [3] pry(main)> DAO::Person.create name: 'Francis' => #<DAO::Person:0x007fe51bc11698 id: 3, name: "Francis", created_at: 2015-12-16 13:22:53 UTC, updated_at: 2015-12-16 13:22:53 UTC> [4] pry(main)> exit
Maintenant, exécutez à nouveau votre client.
$ bin/zss-client [{"id"=>1, "name"=>"John"}, {"id"=>2, "name"=>"Mary"}, {"id"=>3, "name"=>"Francis"}]
Voilà.
Considérations finales
En parcourant le code fourni dans ce guide, vous pourriez penser que de nombreuses étapes n'étaient pas nécessaires, telles que la création de référentiels ou de DTO, et vous auriez raison. Tout ce dont vous auriez besoin pour avoir un service "Personne" fonctionnel serait votre classe de service et votre DAO, que vous pourriez appeler directement à partir de la classe de service. Néanmoins, il est recommandé de suivre le modèle décrit dans cet article, car cela vous permet de séparer la logique de service de la manipulation de votre stockage de données. Les services doivent uniquement se concentrer sur leur logique et les référentiels doivent gérer toutes les interactions avec votre stockage de données. Les DTO déterminent les charges utiles et la sérialisation de vos services, et les DAO ne s'intéressent qu'à l'obtention de données à partir du stockage. Les conventions et techniques décrites dans ce guide sont connues sous le nom de modèle de référentiel, que vous pouvez consulter dans l'image ci-dessous.
J'aimerais terminer en demandant à tous ceux qui trouveraient cela utile de contribuer à la suite de services SOA, en l'étendant et en l'améliorant de quelque manière que ce soit. Toutes vos requêtes forks et pull sont les bienvenues.
J'espère que cela vous aidera à démarrer dans les microservices. Si vous souhaitez consulter le code du service, une version complète est disponible sur GitHub.