From ebe1d1a80aa1a1b775ec436b22398bebd65f29de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=92scar=20Casajuana?= Date: Wed, 14 Nov 2018 17:21:22 +0100 Subject: [PATCH] Updating readme --- README.md | 103 ++++++++++++++++++++++++++++++------------------------ 1 file changed, 58 insertions(+), 45 deletions(-) diff --git a/README.md b/README.md index b443de8..3bb9515 100644 --- a/README.md +++ b/README.md @@ -1,35 +1,42 @@ -# switchboard-operator +Switchboard Operator +==================== [![Build status][build svg]][build status] -![Switchboard operatorstext](https://upload.wikimedia.org/wikipedia/commons/8/8e/Photograph_of_Women_Working_at_a_Bell_System_Telephone_Switchboard_%283660047829%29.jpg "Switchboards operators") +Switchboard Operator (a.k.a. SBO) is a production-ready service used to manage RabbitMQ flows between microservices. -## Introduction +![Switchboard operators image][switchboard operators] -This service aims to manage AMQP (RabbitMQ) connections between our -microservices. It combines two main entities to structure this communication -flow and one to define which actions should be executed: +Introduction +------------ -- Events: Avents are triggered when something relevant happens in a microservice - (user created, email sent, etc), events doesn't modify state. They advice - subscribed queues of anything happened in the system. +Before starting, we recommend you reading [Anand Pate'ls post about Event-driven Microservices using RabbitMQ][event driven microservices using rabbitmq]. Most of the concepts in this software are based on his article. - Format: `microservice-name.entity-name` route `created|modified|deleted` +It combines two main entities to structure this communication flow, and one to define how actions should be executed: -- Tasks: Tasks are queues attached to microservices, listing for new tasks to realize - by the microservice listening +- **Events:** Events are triggered when something relevant happens in a microservice (a user has been created, a purchase is filled, etc); **events don't modify state**. They advice subscribed queues about anything happened in the system. + + Format: `microservice-name.entity-name` route `created|updated|deleted` + + This format means that when you create an event with name `whatever.entity` and route `created`, a queue of name `whatever.entity.created` will be created by SBO. + +- **Tasks:** Tasks are actions which modify state. So every task has custom queues attached to microservices, listening for new tasks to realize. Format: `microservice-name.action-name` -- Actions: You can trigger any of this actions on queue received messages. Actions are similar - to expressjs middlewares, they're executed in order for each received event +- **Actions:** Actions are custom SwitchboardOperator entities triggered on the specific event & route their operator is listening to. Actions are similar to expressjs middlewares, they're executed in order for each received event. + +You probably noticed we're using the word `Operator` here. Operators are recipe files written in yaml for both events and tasks. -This library uses [rabbot](https://github.com/arobson/rabbot) node module to manage the connection with Rabbitmq +> Note: both events and tasks also create one dead-letter queue for each queue created. Which means that you'll end up with at least two queues for each task or event. +This library uses [rabbot](https://github.com/arobson/rabbot) node module to manage the connection with Rabbitmq. -## Configuration example -```json +Configuration example +--------------------- + +~~~json { "rabbitmq": { "host": "rabbithost", @@ -39,25 +46,29 @@ This library uses [rabbot](https://github.com/arobson/rabbot) node module to man }, "tasks": [ { - "eventName": "cfs-emails" + "eventName": "emails" } ] } -``` +~~~ + +The service will automatically create dead-letter exchanges for failed messages, this way you won't lose messages when some operator fails. -**NOTE**: The service will automatically create dead-letter exchanges for failed messages, this way you won't lose messages when some operator will fail. *NOTE*: You should declare all tasks where you want to send your message using `prev2task` or `event2task` plugin. -## Visual representation of topology +Visual representation of topology +--------------------------------- The project exports a visual representation of the configured topology. Just start the server with -``` +~~~bash node app.js -``` +~~~ Open http://localhost:3000/topology +> Note: this feature is not properly tested and may not be working. + ## Operators The actions to be executed when a message is received in a subscribed queue are grouped in a files called operators. Operators should group some common actions in a specific context. The operators are defined in yaml files stored in `operators` folder. This is the way you have to define what should happen every time you receive a message for a specific event. @@ -67,7 +78,7 @@ Each Operator will create its own queue to manage its tasks, so you can have sev An example of operator can be seen -```yaml +~~~yaml # Execute every time a purchase is update name: someUniqueName eventName: events.purchase @@ -107,7 +118,7 @@ actions: options: target: cfs-emails targetRoute: email.send -``` +~~~ ### Available actions to be defined in operators @@ -115,16 +126,16 @@ actions: Just print the received object to stdout. -```yaml +~~~yaml - name: print-log type: log -``` +~~~ #### http It makes a HTTP request, you can set the url using nunjucks templating. Ideal to execute webhooks with your AMQP events. -```yaml +~~~yaml - name: whatever type: http options: @@ -132,13 +143,13 @@ It makes a HTTP request, you can set the url using nunjucks templating. Ideal to method: GET|POST|PUT|etc merge: true|false # We must merge response with the previous message mergeTarget: 'someField' # Where to merge the response? If not specified will be merged on the root level -``` +~~~ #### conditional It checks for defined conditions in the received object and abort execution if some condition is not met. -```yaml +~~~yaml - name: whatever type: conditional options: @@ -146,13 +157,13 @@ It checks for defined conditions in the received object and abort execution if s - field: someReceivingObjField operation: === checkValue: valueToCheckAgainst -``` +~~~ #### mapper It converts the message from the last action executed, to a new object following the mapping. This plugin is using the [object-mapper](https://github.com/wankdanker/node-object-mapper) library behind the scenes, so you can use all mapping options avilable in the library, including wildcards. -```yaml +~~~yaml - name: membershipToEmailMapper type: mapper options: @@ -160,25 +171,25 @@ This plugin is using the [object-mapper](https://github.com/wankdanker/node-obje fields: whatever.name: 'result.fullname' firstName: 'lastName' -``` +~~~ #### prev2task It gets the message comming from the last action executed and send it to a defined task. -```yaml +~~~yaml - name: sendMembershipToEmailQueue type: prev2task options: target: cfs-emails targetRoute: email.send -``` +~~~ #### setter Manually set some object attributes to be consumed for the next operator's action. -```yaml +~~~yaml # Set paid attribte as true - name: setPaidPayloadAttribute type: setter @@ -186,13 +197,13 @@ Manually set some object attributes to be consumed for the next operator's actio fields: paid: true message: 'Payment set to true' -``` +~~~ #### merger deep-Merge specified input source keys to one output target key -```yaml +~~~yaml # Merge meta's ^^ - name: bookingToEmailBody type: merger @@ -202,39 +213,39 @@ deep-Merge specified input source keys to one output target key - 'user.metaDefaults' - 'user.transportDefaults' targetField: 'transport.somDeeperField' -``` +~~~ #### telegram In order to use telegram plugin you must set the telegram token in your config: -```json +~~~json "plugins": { "telegram": { "token": "xxxxxxxxx:yyyyyyyyyyyyyyyyyyyyy--zzzzzzzzzzzz" } } -``` +~~~ Then you can define your operator action as it follows: -```yaml +~~~yaml # Send membership to logs for debugging purposes - name: logMembership type: telegram options: chatId: '-288888888' template: 'A new membership with {{ id }} has been registered' -``` +~~~ ## Usage with docker Create your own operators under the folder `operators` in yaml format. The service will autoload all operators. Then just run docker-compose. -``` +~~~ docker-compose up -d -``` +~~~ ## Known limitations @@ -250,5 +261,7 @@ docker-compose up -d MIT +[switchboard operators]: https://upload.wikimedia.org/wikipedia/commons/8/8e/Photograph_of_Women_Working_at_a_Bell_System_Telephone_Switchboard_%283660047829%29.jpg "Switchboards operators" +[event driven microservices using rabbitmq]: https://runnable.com/blog/event-driven-microservices-using-rabbitmq [build status]: https://travis-ci.org/alvarium/switchboard-operator [build svg]: https://img.shields.io/travis/alvarium/switchboard-operator/master.svg?style=flat-square