Microservices with Node JS and React
The project contains a submodule, clone with these parameters:
git clone –recursive https://github.com/josecho/MicroServicesNatsStreamingBlog.git
After cloning the repository, let’s go to the branch where the code we are going to talk about was developed.
git checkout -b managinNatsClient
Singleton is a creational design pattern that lets you ensure that a class has only one instance while providing a global access point to this instance.
The Singleton pattern solves two problems at the same time, violating the Single Responsibility Principle
On the internet you can find many pages that explain its operation in greater depth.
Managing a NATS Client
Firstly, indicate that in the application we are going to talk about (we already did it before), we have implemented an Event Bus called NATS Streaming Server to handle communication between services using events.
During the code development process, we have reached a point where we need to start managing communication between services in order to publish and receive events among them. In other words, we must manage a NATS client. For this reason, a branch called managinNatsClient has been created. In it, you can see all the commits created to follow the entire development process. Specifically, this process has started in the Tickets Service.
git checkout -b managinNatsClient
Let’s see the first step taken. In this commit we can see that when a ticket is created, Tickets Service publishes an event to communicate this action to the rest of the services. For this, it is using a client that is not yet defined or imported (at this moment the compilation fails).
We’ve got our publisher and now it just needs an instance of a Nats Client in order to successfully publish stuff. We must decide where to place the client in our code.
At first, the index.ts file (ticket module) seems the best option to locate the client. Inside this file, we can see how Mongoose makes the connection as well and the application is working correctly.
Singleton Mongo Connection
We’re going to try to build something very similar to Mongoose, where we’re going to have some kind of object that internally keeps track of some client and makes it available to everything else inside of our app.
When we connect with Mongoose, Mongoose internally keeps a record of all the different connections that exist. We can open up any other file inside of our project and import Mongoose and obtain a copy of Mongoose that is already connected to some server. So we could freely make use of Mongoose or through the different models that we create to reach out to MongoDB, make queries, and whatnot.
After running the code, shown in the image above, any other file inside of our project can import Mongoose and it will get an already pre-connected, pre-initialized version of Mongoose as well.
We use Mongoose technically through the Ticket Model, but we could technically import Mongoose and use it to reach directly out to our database without having to worry about initializing any connection or anything like that.
Here’s what’s going on behind the scenes inside Mongoose.
Singleton NATS Client
However, the Node NATS Streaming library that we are using to connect to NATS establishes the connection in a very different way.
So inside of the publisher file (nats-test module: in this module we have carried out tests to verify that the NATS server responded correctly to the publishing and reception of events), when we connect with NATS, there is not some internal connection or internal object keeping track of this connection inside of this NATS library. Instead, when we call NATS to connect, it directly returns to us the client.
So this client is what we need to somehow manually share among all the different files inside of our project.
As we mentioned before, the index.ts file (ticket module) seems to be the correct location to proceed with its initialization, in the same place where the mongo connection is made. We’re going to have a NATS Client object and we want to somehow share that with a bunch of other files inside of our project.
But that starts to raise a really big issue, what is called a circular dependency.
Some files import each other, mutually, as seen in the image above, and create this problem. That’s something we can technically do. But it would be really fantastic if we could figure out some way to avoid creating this cyclical dependency.
In order to avoid this, as we said before, we are going to try to build something very similar to Mongoose, where we are going to have some type of object that internally keeps track of some client and makes it available to everything else inside of our app. We will follow the approach shown in the following diagram.
Steps taken in the implementation
Although you can also see the same implementation of the pattern in different programming languages on the same page. But what we try to show in this post is how this pattern is implemented in ES6+.