Now we can also see the rest of our microservices have started up successfully and we can go back to
Postman and make sure all of our functionality is still working as expected.
So I'll go ahead and create a new user so that we start from scratch.
So I'll create a new user by targeting our auth service slash users route.
I've gone ahead and created the user.
I'll go ahead and log in with its credentials, so make sure I have the correct email test user to I
have my JWT set.
So now if I launch a request at localhost 3000 slash reservations to send a post request to create a
reservation with our typical reservation payload, I can see if I send this request off, I come back
with a 201 created response.
So our reservation has been successfully created.
And then if we look at our Stripe dashboard, I'll go ahead and refresh and we can see we have a new
$45 payment that has just been processed.
And if we go to our email provider, you can see I have a new email from Sleepers saying that my payment
has completed successfully so we can see that our microservices are working just as they did before.
Even though we swapped out our transport layer, we didn't have to change any of our underlying code
thanks to the nestjs microservice abstraction.
So now that we have rabbitmq set up, let's show the differences in our retry logic by going to the
payments controller again and we'll rethrow that error in the same spot.
So let's go ahead and throw that error when we create the charge and see what happens now.
So now after Recompiling, if we try to create a reservation again, we get that 500 internal server
error as we expect from the reservation service.
Now if we run Docker container LS in another terminal and get the container ID for the payment service,
let's go ahead and restart it by running Docker container restart and then pasting in the container
ID so that our container restarts.
So now that our container restarted, you can see that it didn't try to reprocess that failed message
it originally received.
And that's because by default, Nestjs is automatically acknowledging all the messages that we process
in Rabbitmq back to the broker.
So we actually have to explicitly tell it to not automatically acknowledge all these messages by going
back to the main.ts.
And in the options there's a property called Noac that if we set to false, that means that we won't
automatically AQE and we need to do this ourselves.
So let's go ahead and see the effect of this.
After our container restarts, we will send a another message to create a failed reservation.
So that this message gets retried.
I'll go ahead and send the failed message off and we can see we have the 500 in reservations and the
error in payments.
So now we'll go ahead and run that same command where we restart the payments container, look at the
container ID and run docker container restart and go ahead and restart it.
So let's see the behavior now as payments restarts.
So immediately after starting up here, you can see that it actually retried the message and ran into
the same exact error that we had originally.
So this is very powerful because unlike the TCP microservice, we actually have state here because of
our queues, right?
So after this message fails to get reprocessed, the broker never receives the Ack and next time we
ask for the next message, well, we get that failed message and we can replay it.
Maybe if a service was down, we can retry it.
And that way we don't lose the message.
So this is a big benefit of using asynchronous messaging like Rabbitmq.
Additionally, we also have the added benefit of now having a queue so that if we can't process all
these messages at once, like in TCP, we'll be hit with a bunch of requests at once.
Instead, with a queue, we can process our messages in a controlled fashion so that we don't overload
our container with work because we have this maintain state of messages.
So this is another big benefit of using async messaging like Rabbitmq.
And thanks to Nestjs abstracted microservice, we don't really need to change out a lot of functionality
as we've seen.
Now I want to show you how we can actually acknowledge these messages manually in case we want to handle
this on our own.
Maybe persist the message to a dead letter queue.
We actually can get access to the current message context by using the add context decorator and.
And this will be of type rmq context.
So now that we have access to the rabbitmq context, we need to get access to the channel by calling
context dot get channel ref.
And then we need to get access to the original message, which is just the message that we are currently
on.
We can call context dot get message.
So this can also be useful if we need to explore any of the other metadata on the message.
However, we're interested with actually asking the message.
So if we call channel dot ACC and then pass in the original message, we will actually acknowledge our
message.
And this won't get repeated because we're asking the message and then we're throwing an error.
So let's go ahead and actually see what this looks like.
Now after our container restarts, you can see that it reprocesses the message.
However, now we've actually act.
So if we try to restart the container like we did before, let's go ahead and see what happens.
I'll take the container ID from payments and go ahead and restart this container.
We should expect to see the message not get reprocessed any longer because we acknowledged it before
we threw an error.
So let's see as it starts up now.
So payments has started up and you can see it no longer processed that message because we acknowledged
it.
It took it off of the queue and there was no longer the message to process.
So we can have much more fine grained control over what messages we want to acknowledge, when we want
to acknowledge them.
And we can essentially replay these messages whenever we want by manually acknowledging which is super
powerful.
And finally, I'll just go ahead and remove the error now.
So now we're still acknowledging the message.
As soon as we return the data back to the caller, which is what we want to do.
So I hope this has been a useful lecture for you to understand how we can easily plug in different transports
into nestjs microservices and take advantage of the asynchronous messaging so that we can implement
retries by re queuing messages and to make sure that we don't have to process all of our messages at
once, we can take advantage of a queue.