Let’s implement a real-time package tracking app with RabbitMQ and Web socket using Go 🚀

Abdulsamet İLERİ
ITNEXT
Published in
3 min readJul 12, 2022

--

What is this app?

This application provides real-time package location information using vehicle information because vehicles carry packages. So that it answers the questions like where is my package now, where is it going? (Currently, I didn’t implement broadcasting on WebSocket. You can think of communication 1-1)

Application Architecture

Overall architecture

Source Code

https://github.com/Abdulsametileri/package-tracking-app

Websocket

There are many materials about WebSocket, but I strongly recommend that you read WebSocket’s RFC document.

This protocol has two parts: a handshake and data transfer.

Handshake flow

Once the client and server have both sent their handshakes, and if the handshake was successful, then the data transfer part starts. This is a two-way communication channel where each side can, independently from the other, send data at will.

RabbitMQ

I think RabbitMQ documentation is excellent. I recommend that you learn basic concepts like (queue, exchange, etc.) by following their tutorial and reading the AMQP protocol specification.

AMQ Main Entities

Websocket Handler

upgrader.Upgrade upgrades the HTTP server connection to the WebSocket protocol. It checks the handshake process; for example, it checks whether request headers are correct, such as upgrade=Websocket and connection=Upgrade equal or not.

Handling WebSocket close state

To handle the WebSocket closing handshake, I use wsConn.ReadMessage() When the client navigates another page or something like ReadMessage() returns a non-nil error. When the error is not nil, I call context’s cancel function. In doing so, the context’s done channel is closed so we can close the underlying TCP connection and return it from our handler, as shown below in the first select case.

Handling WebSocket states

In the select statement default state, we can listen to our package_status queue; when the new package status arrives, we can pass it information to the WebSocket. Note: p.PUseCase.TrackByVehicleID(ctx, vehicleID)This method is based on <-chan amqp.Delivery . We get package info from this channel when a new message comes in our queue.

Package Usecase

In our use case, there is no specific rule in there. So we can get bytes message from RabbitMQ client and marshal our package struct format.

RabbitMQ Client

I open a TCP connection and a channel (virtual AMQP connection) within it. Channels are full-duplex, meaning that one channel can be used to both publish and consume messages.

I configure queue with declare keyword -create if not present, otherwise continue- and register consumer chan on it.

I continuously listen within the (c *rabbitmqClient) ConsumeByVehicleID method. I use the message_id property to differentiate messages.

Note: I use (c *rabbitmqClient) Publish method on the main method for only test purposes.

Put it all together

When we run the application, we see the package location every 3 seconds.

Running App

Source Code

https://github.com/Abdulsametileri/package-tracking-app

References

My RabbitMQ Notes

https://datatracker.ietf.org/doc/html/rfc6455

https://www.rabbitmq.com/protocol.html

https://www.sohamkamani.com/golang/context-cancellation-and-values/

https://www.amazon.com/RabbitMQ-Essentials-distributed-scalable-applications/dp/1789131669

--

--