If you have an enormous application that grows year by year, there will be a day when you realize that in your team there are only one, or maybe two people who understand code. So, what shall you do with this knowledge? There are few possibilities:
- Rewrite whole app like Microsoft is doing with Windows.
- Refactor code - pay technological debt.
- Do nothing just live with this (many companies are working like this way).
However, there is another choice microservices.
Imagine a system splitted into plenty of small apps communicating through one message broker. These small apps would be easier and faster to analyze. We, developers could focus only on logical part of application and write code instead of analyzing thousands of code lines.
Ok. We now know that microservices could be the resolution for our problems. But we have heard that this approach is difficult to design and even more difficult to implement. How can we do this? Well, we have many choices, but I would like to focus on using great framework called Moleculer.
It has its own CLI, allows to manage nodes and supports plenty of message brokers.
Shall we start?
This article will briefly explain how to create a project, configure a few services and what we can get for free from this framework. Let's start from installing moleculer cli tool.
Before making a new project, let's talk a bit about the gateway. Having a gateway in the molecular project is not obligatory, but without it nobody will be able to access services from outside the message broker. I think that the goal of the project is to give the user API and this is why we are adding a gateway. By default, moleculer creates gateway with Api Gateway mixings, which creates api endpoint for each service. This gives us a lot of for free. When we have successfully installed the cli then we can create project.
Moleculer asks us few questions
For demo purposes main project will contain Gateway, use AMQP transporter (for RabbitMQ), communicate with other nodes, collect metrics and check tracing. At the end moleculer ask us if we want to automatically run npm install. Results?
After opening project in vscode we can see project structure. Most important files in the project are:
There is also index.html file, which shows moleculer console definition. File moleculer.config.js contains all available properties, which can be changed. Beginning from the `nodeId` ending on the load balancing, tracing, and metrics. We will leave all properties in default configuration beside 2 of them:
Browser displays instance configuration details, so we can see what was enabled, which transporter is used and what are its options setted. On the top of the site there is a menu containing 3 other tabs:
- Greeter service - default page for accessing greeter service api. I would like to stay here for a while and explain how these tabs for services work. Unfortunately, if we add new service to the moleculer, it will automatically join with broker, show in nodes and services tab. But we will not see new tab for restful requests. These tabs are statically written in the index.html file. To add next service page, menu and requests properties in JSON object have to be modified. For demo purposes we will use curl utility to access endpoints.
- Nodes - lists all available services. Displays nodeId, type, moleculer version, address, host name, and status (is it working or terminated). At the moment it shows only one node called master.
- Services - here we can find all services available for public access. Right now there are two: api and greeter.
Shall we try one of them? Let's run greeter.welcome
Great, it works!!!
Project is created and configured properly. Now let's see Greeter service definition file.
Let's explain what this file contains:
- name - should be unique service name,
- dependencies - contains names of all services, it will wait till these services are not up and running,
- settings - service settings, I will write more on that later,
- hooks - we can define hook for actions, more on that here: https://moleculer.services/docs/0.13/actions.html#Action-hooks,
- actions - are public methods available in API to the end user,
- events - here is definition of the events, to which our service is listening,
- methods - private methods available for this service - these methods can be used only in this service,
- last three - created, started, and stopped are service's lifecycle methods.
Ok. Now remove greeter.service.js file. What happened? There is no need to restart the application or refresh browser. Services page had automatically refreshed and now it shows only one endpoint given by GatewayAPI mixin.
New Tax service
If on your computer there is already a running metrics instance from another node, don't forget to change the port of the Prometeus. The following error is telling us that there is Prometeus started at port 3030. Change it in the moleculer config file to different port.
Awesome!!! We deployed newest tax service. I want to try it out, don't you?
It's alive!!! Working like a charm.
Let's say that our calculation has to be shared with any other service. How to handle this? Events are useful to achieve this goal. First create new project called mailing. It will do nothing beside console.log the provided parameters. New service will have implemented only events part.
After starting project, another node appears on the console. But how our tax service can communicate with mailing? We cannot call action, because it does not have any. Now we will use a broker to emit event in the calculated action from the tax service. To do this just add one simple line. First attribute of emit method invocation is event name (the same as in mailing service) and second attribute are params, which will be send to the recipient.
And here is the result visible in the console of the mailing service
Pretty simple, don't you think? Probably you are thinking: Ok, but why use events? Perhaps we could implement action in mailing and call it. Yes, we can use
But there is a small difference between events and directly calling actions. During event emitting there is a possibility to decide if this event should be propagated to all of the nodes/services or maybe just one. By using broker.call we can only call one action at the time.
Today our boss came back with a great idea of changing the tax.calculate method by adding parameters, which will tell what the rounding. But many customers are using existing action in their environments. We want to implement a new version, but we do not want to break our customers systems.
What shall we do?
Nothing easier. Create project tax2, implement calculate method and add version property just after the name of the service to tell moleculer that there are 2 instances of one service.
I cannot wait to see the results
In this article we have seen, how fast we can create microservices architecture in node.js by using Moleculer. I explained the small percent of functionalities, which are available in this awesome project. There are out of the box features, like: authentication, db mixin, which creates default actions eg. put/post/get/delete for entity scheme, there is also validation and more. If I would have to explain everything, it could take months. What I wanted to was to interest you, dear reader, to go deeper and check if this framework is worth your attention.
In my opinion it is.