NestJs Microservices with RabbitMQ

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hello guys in this video we're going to see how we can establish communication between different services using rabbit mq we're going to see how we can emit an event to a rabbit mqq and then consume it and we're also going to see how we can Implement RPC which follows the reply request pattern so our consumer is going to reply back to our producer with some response so let's go ahead and see what we have here I've created two different njs projects I called them producer and consumer for the sake of this video I used Nest new the normal command and I've deleted some files that I don't really need now if you take a look inside of our producer project in main.ts we are exposing our application to the internet on Port 3000 so we are ready to take some HTTP requests now let's see how we can connect our producer to the rabit mq server let's go inside of our producer folder and then here we need to install njs microservices package if you get this error where it says that we have some uh conflict inversions in this case what solves it for me is using the version 9 for the package and you also need to install amqp lib and amqp Connection Manager those packages are specific for rabbit mq and now I'm going to open a terminal and then go inside of the consumer project and install the same packages now inside of app module inside of our producer we need to create a RIT mq client instance so that we can send messages to rabit mq to do that all we have to do is import client's module from njs microservices and we need to use the register method it takes an array of different client options and then here we should give our client a name it could be anything this is going to be the name of the injection token that we use whenever we need to inject this client so that we can send messages or emit events we need to specify a transport for rabbit mq we use rmq and then we need to pass in some options for our Revit mq server in this case I'm connecting to Revit mq locally on my machine and then this is the Q name that we're going to be producing messages to I'm going to call it orders Q now inside of our producer again I'm going to go ahead and create an orders module and now I'm going to get rid of some files that I don't really need so we end up with a controller a module and a service I went went ahead and created a rout Handler place order which is of HTTP method post and we expect an order from the request body let's go ahead and create the order dto and let's just keep it simple so we're just going to expect an email a product name and the product quantity so this is how our order dto is going to look like the email of the customer making the order and then the product name that they chose and the quantity of course we're just keeping it simple for the sake of the example so now here we can specify order dto is what we're expecting now inside of our order service let's go ahead and create a place order method that is also going to expect the order dto and we're going to call this method from our controller so here we're going to say say return this do order service do play order and then we need to pass in our order now the goal here is that every single time an order is placed or someone calls this endpoint we need to send a message to Rabbit mq about this event happening so that some other microservers can consume this event and then every time someone places an order the other micros service might maybe send an email of the order just confirming it to the customer so let's see how this can be done now we previously said that to be able to send messages to rabit mq we need to create a rabbit mq client instance which is what we've done here and then we also said that the name that we set here is going to be the injection token name that we use whenever we're injecting this client to send messages so let's do that now TI of order service let's create our Constructor and then use at inject decorator to inject a token and the token name is going to be orders uh service which is the name that we specified for our client and then here let's just just call it rabbit client for example which is going to be of type client proxy which is from njs microservices and then now if we take a look here we can see that we have different methods we previously said that we're going to emit an event and we're not really going to care about the response so all we care about here whenever a an order has been placed is just a notifying rabbit mq and sending a message that this event has occurred that an order has been placed so this is why we're going to be using Emit and it takes a pattern and some data let's call our pattern uh order place for example and then the data is going to be the order so what this does is it simply uh sends a message to rabit mq okay the pattern is going to be order placed and then the payload is going to be the actual order and then here we could just return some message order the place for example now if we go ahead and try to run our server we're going to see that we have a dependency issue so order service is not known so that's because this client here registered is not Global in our application so one way to fix this is instead of having it inside of our app. module you can add it or register it inside of orders module of course we need to make the Imports and with that in place as you can see now the server is running correctly and now if we open Postman and make a call or a request to this endpoint okay with email product name and quantity so we're respecting our dto as you can see we got a message saying order placed and we didn't get any error although we don't have a consumer listening to that event yet and if you take a look here in rabbit mq management inside of the Q tabs we can see that an order que has been created now and we can see that there's one message ready inside of this queue it's not yet consumed and we don't really have a consumer yet to consume it so let's go ahead and fix up our consumer connected to Rabbit mq and listen to that orders CU to receive those messages so back nvs code this time inside of the consumer folder we're going to go to main.ts and for the consumer we don't really need to be listening to http request it's going to be purely a micros service so here what we're going to do is Nest factory. create micros service all we have to do is pass pass in the app module to our create microservice method and then we need to pass in the options so if you take a look here again we are just specifying the transport protocol we are choosing rmq that's because we're using rabbit mq as a message broker and then we're passing in the same options that we have in our uh producer client so we have the same URL connecting to our rabit mq server and then we are specifying the queue that we're going to be listening to so this consumer is going to be listening to to orders que what we've done is the first step but it isn't enough to uh consume the message as you can see it is still stuck inside of our queue inside of rabbit mq the next step is to actually register event handlers so what we need to do is to go to our controller in the consumer and this is the entry point for uh our event handlers so it would not work if you try to actually have handlers inside the service or a provider it should be inside of the controller and here we need to use event pattern and then we need to specify the pattern that we're going to be listening to and here is going to be order list which is the same one that we are actually emitting here from our producer and now here let's call this handle order place and then here we're going to get a payload so we're going to use the payload decorator from ns/ microservices again and this is going to be the data that we're going to receive now we know that our producer is producing orders of type order dto so here let's expect an order and let's go ahead and create the order dto here and don't forget here this is a different project the consumer is a different njs Standalone project so here again order. D.S and let's just copy the same dto that we have here and here we can specify the type as order dto now inside of app service let's go ahead and also create handle uh order placed which is going to get an order and here what we could do is we could say for example received a new order and then here we could say for example customer and then we can show the email of the customer so order. email and now in the controller let's go ahead and call this uh method and pass in the order npm Run start Dev as you can see we just received a new order which is customer Jeff and if you go back to Rabbit mq management here we can see that there's no more messages the message that we had here has been consumed correctly by the consumer now here typically for example example you might have uh some functionality such as sending an email to a user confirming the order that has been placed and this is inside of the consumer it does not know about the producer and the producer does not know about the consumer they are both independent from each other and rabbit mq is connecting them both just to make sure that everything is working correctly let's press it three times for example so those are three new orders if you go back to our consumer we can see that we have three new orders here so far we've seen how we can actually emit or send a message to Rabbit mq and then forget about it we're not waiting for a response and in case the consumer was asleep or down the server would be kept inside of rabbit mq it would be kept inside of the queue up until some uh consumer wakes up and then receives it and processes it but what if we have a case where we need to actually receive a response from the consumer so what if we send a request message and then we're waiting for a reply let's see how we can Implement that back to our producer project I've created a second route Handler of type get called get orders which is supposed to get the orders made now we're going to assume that we need to send a message to Rabbit mq so that we can uh receive or fetch those orders from the actual consumer so to do that we could use the send method instead of emit emit is used if you are sending something and we don't really care about response but we use send whenever we have uh a remote server and we need to fetch some response from that server so this is similar to the request reply pattern you send a request which is the message here to rabit mq to to the actual Q ERS que and then the consumer is going to play the role of an RPC server a remote uh server that is going to consume the message from the que and then return a response here using a reply to Q behind the scenes now if you take a look at send we can see that it also takes a pattern and some data now for sending messages it is recommended by the sjs team to use a pattern similar to this so we specify a command we could call it fetch orders for example and then we need to pass in a payload just like we did here whenever we were emitting but this time we don't really care about sending anything so I'm just going to send an empty object now back in our consumer project inside of the controller just like we did with event pattern we need to do the same but this time with message pattern and this time the pattern is this one command fetch orders so let's specify that so we're going to be listening to this and then here let's call it get orders for example we don't really need to take anything here and let's go ahead and create a method in our service called get orders so I've created this get orders method here and I've also added an orders array in our app service and then inside of handle order placed so anytime we get new orders uh I'm not just going to log but I'm also going to push the new orders into this array so that here we can return the list of orders anytime we uh request for them now let's see what happens and just to remind you inside of our orders controller inside of the producer project where we have the route Handler get orders let's make a request to this and see what happens whenever we send a message to rabit mq with this pattern expecting to get some orders so in Postman in/ orders with the type get if I hit send as you can see we got an empty array but if I go ahead and place some orders four orders for example and hit send this time the consumer or the RPC uh server in this case is going to return those orders if you go back here if you take a look at the terminal the consumer terminal we can see that we got four new order events and we also return those orders whenever we requested them from here and just to highlight again the difference between Emit and sand let's say our consumer was down so here it's offline and we went ahead and placed some new orders so we're sending messages to rabit mq as you can see everything is perfectly fine here we're still getting the responses if you go back here and if you refresh in rabbit mq management we can see that now we have six messages inside of our rabbit mqq orders Q waiting to be consumed so let's go ahead and run our consumer now and as you can see we received those orders and now if you go back we can see that we have zero messages ready inside of the orders queue they have all been consumed as soon as the consumer went up however the same can be said if we turn it off again and this time we uh try to request some data from it so now we we're using send instead of emit if we hit send as you can see we're still waiting for a response but we're never getting that response because it is down here the consumer is down now so it's going to be stuck here up until the consumer is up again then in that case we're going to get our response but of course we don't know how long the consumer is going to be down so in the case of RPC whenever we requesting uh something and we're waiting for a reply we could set a timeout here so for example we could say pipe and then here we could specify time out and we could say for example 5,000 milliseconds meaning 5 Seconds now if we stop the consumer again and then try to make a request it's not going to be waiting for a long time it's just going to be waiting for 5 seconds now as you can see after 5 Seconds it through an error of course you can handle that error in a better way but this is just to show you that it would be a good idea to implement timeout whenever you're using RPC now in case you want to access some more information about the request uh being made inside of your consumer inside your message handlers or event handlers what you could do is you could use the context or CTX decorator and it's of type rabbit mq context and this way we can see that we can get a channel reference so the Channel we can even get the pattern in this case it would return this command fetch orders or we could also get the whole message being sent so I've already logged a message here if you take a look we have Fields properties and then the actual content containing the data and the pattern if you're familiar with rabbit mq you know that those are different properties that are present in a message and that can be configured when sending a message so for example if you take a look here correlation ID this this is a very important property and it's being set behind the scenes by nestjs normally if we're using a package such as amqp lib when where we're creating our own uh rabit mq client we would need to set this value uh in our code manually but this is handled by njs just quickly to explain what this is uh basically whenever you have an RPC server in this case our consumer so it's consuming a message and then it needs to prepare a response and then return it back to the the main producer or the client so to be able to match which response belongs to which request since we might have a lot of requests and responses we would map them using the correlation ID so this is why it's used another important property here in the scenario of RPC is the reply to this specifies the Q name that the RPC uh server aka the consumer here is going to use to send the response to so we have our orders queue which is the queue that our producer is sending messages to inside of rabbit mq and then we have this consumer or this RPC server consuming from the orders queue whenever they get that request or that message prepare a response they need to send that response back to the main producer to do that they need to do it inside of a que inside of rabbit mq so they also need to play the role of a producer to send that message so we also need a second Que in this case which is the reply to now you might not have known that because this happens behind the scenes njs abstracts all of that work so we don't really have to Tire ourselves with it I don't want to make this video very long so quickly in in case you want to actually uh specify those message properties maybe modify them maybe you want to set a priority for your messages or maybe you want to set an expiration so for example we've seen previously that we had some ready messages inside of our queue in case you don't want them to be waiting forever you could set an expiration which would be a time to live so for example you can set it for 10 seconds after 10 seconds if that message is not consumed by any consumer it would be removed from the queue basically you would need to create an rmq record Builder set the options of that message and then you would need to call the build method then after that you can use send just like we've done and you can access those different properties here just like we've seen here using this decoration and that's pretty much it also in case you want to read your uh connection to your rabbit mq server dynamically from a config service or from an NV file you could just like we've seen in many uh videos before use Factory and then you would inject the config service and then here you could return the client proxy factory. create and then here you set your rabbit mq options so this is something we've seen in many videos uh it's also present here so a quick summary uh if you want to send a message or produce a message to Rabbit mq we would need to create a rabbit mq client uh instance to do that we could use the client's module from ns/ microservices and then here we could pass in some options we need to specify the name which is going to be the token that we inject and then we need to specify the transport lay layer here we specify rabbit mq rmq and then we need to pass in the options that rabbit mq takes such as the Q name this is going to be the queue that we're going to be producing messages to and then of course the URL for our rabbit mq server now in case we want to use that client all we have to do is just use the at inject decorator and then we specify the token name and the Revit client is going to be of type client proxy and we have two different ways of actually sending messages we could either use Emit and of course we need to specify a pattern and then pass in the data or our payload and with emit we just send a message and we don't really care about a response the message goes to the queue and that's it on the other hand if you use send instead of emit of course it's it shares some similarities so we can specify a pattern as well and we can also send a payload but the difference here is that we are subscribing to this and we are waiting for a response from the consumer so here we send a message to Rabbit mq it is going to the same orders Q as well that you specified here but this time we are going to be waiting until a response is returned now that's it from the producer side let's go to the consumer now if we go to the controller we can see that the controller is the entry point so this is where we would use at event pattern and at message pattern event pattern is used to handle events here of course we specify the event name and then we could have something happen here and for messages whenever we need to process a message and then return a response we use the message pattern decorator and then here we specify the command and we also said that we could access the payload by using the payload decorator and we could also access the context for uh the request we can get some more information about that request about the message maybe about the properties and so on now of course for that to work in side of the consumer we have to go to our main.ts and here we should either have a hybrid application or a micros service so here we went ahead and created a micros service application we passed in the app module and then we needed to set the options of rabit mq we set the transport to rmq and then we need to specify the options the queue that we're going to be consuming messages from and then the URL for our rabbit mq server and of course here we need to say app. listen to start the micros server and with that in place we are now ready to start handling different events and different messages so now we can properly consumed from the orders CU if this video was helpful I would really appreciate it if you subscribe like and give me your feedback if you have any other video ideas please leave them down in the comment section thank you for watching and I will see you next time
Info
Channel: Computerix
Views: 1,439
Rating: undefined out of 5
Keywords: Nestjs, RabbitMQ, Microservices, Microservice
Id: JJrFm8IrYTQ
Channel Id: undefined
Length: 23min 21sec (1401 seconds)
Published: Sun Mar 10 2024
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.