<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ message broker - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Browse thousands of programming tutorials written by experts. Learn Web Development, Data Science, DevOps, Security, and get developer career advice. ]]>
        </description>
        <link>https://www.freecodecamp.org/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ message broker - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Thu, 28 May 2026 16:47:23 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/tag/message-broker/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ How to Build a Real-Time Notification System with Go and Kafka ]]>
                </title>
                <description>
                    <![CDATA[ By Hermann Rösch These days, applications need to have instant data access and processing capabilities. Whether it's updating real-time stock trades for financial institutions or navigating through live traffic data, the ability to process and react ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/build-a-real-time-notification-system-with-go-and-kafka/</link>
                <guid isPermaLink="false">66d45f313dce891ac3a96802</guid>
                
                    <category>
                        <![CDATA[ Apache Kafka ]]>
                    </category>
                
                    <category>
                        <![CDATA[ golang ]]>
                    </category>
                
                    <category>
                        <![CDATA[ message broker ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Fri, 25 Aug 2023 21:41:27 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/08/Go_Kafka_Vert_Rev2.svg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Hermann Rösch</p>
<p>These days, applications need to have instant data access and processing capabilities. Whether it's updating real-time stock trades for financial institutions or navigating through live traffic data, the ability to process and react to data in real time is crucial.</p>
<p>In this tutorial, you’ll delve into the mechanics of <strong>Kafka</strong> and then integrate it with <strong>Go</strong> to develop a real-time notification system.</p>
<p>In order to understand this article fully, you should have prior knowledge of <a target="_blank" href="https://go.dev/tour/concurrency/1#:~:text=A%20goroutine%20is%20a%20lightweight,happens%20in%20the%20new%20goroutine."><strong>Goroutines</strong></a>, the <a target="_blank" href="https://gin-gonic.com/docs/introduction/"><strong>Gin</strong></a> framework, and containerization tools like <a target="_blank" href="https://www.docker.com/"><strong>Docker</strong></a>.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ol>
<li><a class="post-section-overview" href="#heading-what-is-kafka">What is Kafka?</a></li>
<li><a class="post-section-overview" href="#heading-how-to-set-up-the-project-workspace">How to Set Up the Project Workspace</a></li>
<li><a class="post-section-overview" href="#heading-how-to-create-the-user-and-notification-models">How to Create the User and Notification Models</a></li>
<li><a class="post-section-overview" href="#heading-how-to-set-up-the-kafka-producer">How to Set Up the Kafka Producer</a></li>
<li><a class="post-section-overview" href="#heading-how-to-set-up-the-kafka-consumer">How to Set Up the Kafka Consumer</a></li>
<li><a class="post-section-overview" href="#heading-lets-test-the-real-time-notification-system">Let's Test the Real-Time Notification System</a></li>
<li><a class="post-section-overview" href="#heading-wrapping-up">Wrapping Up</a></li>
</ol>
<h2 id="heading-what-is-kafka">What is Kafka? 🤔</h2>
<p><a target="_blank" href="https://kafka.apache.org/intro">Kafka</a> is a distributed event streaming platform. Initially developed by LinkedIn, Kafka was subsequently contributed to the Apache Software Foundation and made open-source. This transition marked its role as a key participant in real-time data streaming.</p>
<p>More than a simple communication tool, Kafka is an “event broker” — a system that controls and handles events or messages between various applications or services. It can handle massive daily event volumes as a distributed event streaming platform, guaranteeing that data is seamlessly transported and analyzed in real time.</p>
<p>Apart from its fundamental role as an event broker, Kafka offers durability, scalability, and fault-tolerance features. It also helps ensure that large-scale data streams are managed efficiently and reliably with very low latency.</p>
<h3 id="heading-kafkas-core-components">Kafka’s core components ⚙️</h3>
<p>Now that you’ve been acquainted with Kafka, let’s dive into the main elements that make up its architecture:</p>
<h4 id="heading-events">Events</h4>
<p>An event records the fact that “something happened”. It can be thought of as a message or a piece of data representing a change or an action. In the context of our real-time notification system, you could consider an event as follows:</p>
<ul>
<li>Event key: <code>“1”</code>   (representing the user <strong>ID</strong> for <strong>Emma</strong>)</li>
<li>Event value: <code>“Bruno started following you.”</code></li>
</ul>
<h4 id="heading-brokers">Brokers</h4>
<p>A Kafka broker is a server that runs the Kafka software and stores data. While large-scale production setups often involve multiple brokers across several machines, you’ll use a single broker setup for this tutorial.</p>
<h4 id="heading-topics">Topics</h4>
<p>Topics in Kafka are similar to folders in a filesystem. They represent categories under which data or events are stored. For instance, an example topic name could be <code>"notifications"</code>.</p>
<h4 id="heading-producers">Producers</h4>
<p>Producers are entities that publish (write) or send messages to Kafka, such as a Go program or a service. When a producer has an event to send, it chooses a topic to address the event to.</p>
<h4 id="heading-consumers">Consumers</h4>
<p>Consumers read and process events or messages from Kafka. After producers send messages to topics, consumers can subscribe to one or more topics to receive the messages.</p>
<h4 id="heading-partitions">Partitions</h4>
<p>Each topic in Kafka can be further divided into partitions. Think of partitions as segments within a topic that enable Kafka to manage data more efficiently, especially in setups with multiple brokers. </p>
<p>You’ll stick with a basic configuration without delving into multiple partitions, but you should understand their role in larger Kafka deployments.</p>
<h4 id="heading-consumer-groups">Consumer groups</h4>
<p>While individual consumers handle messages from specific partitions, consumer groups manage coordination across multiple consumers. </p>
<p>A consumer group consists of multiple consumers collaboratively processing messages from different partitions of a topic. This ensures that each message from a partition is processed by just one consumer in the group, allowing for efficient and scalable consumption. </p>
<p>Think of it as a team of consumers working together, with each member responsible for messages from specific partitions, ensuring no message is overlooked.</p>
<h4 id="heading-replicas">Replicas</h4>
<p>Replication ensures data safety. In larger Kafka deployments, storing multiple data replicas is common to help recover from unexpected failures. </p>
<p>You won’t be using replicas in this tutorial, but it’s beneficial to understand their significance in ensuring data durability in Kafka.</p>
<h4 id="heading-kraft">KRaft</h4>
<p><a target="_blank" href="https://developer.confluent.io/learn/kraft/">KRaft</a> is Kafka’s own consensus protocol introduced to eliminate the need for <a target="_blank" href="https://kafka.apache.org/documentation/#zk_depr">ZooKeeper</a>. In short, KRaft manages metadata directly within Kafka, providing scalability, simplicity, and improved failover, among other benefits.</p>
<p>To tie all these components together, here’s a visual representation of Kafka’s core architecture, illustrating a broker, topics, partitions, and consumer groups:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/Kafka_Architecture_Transparent_V2.png" alt="Image" width="600" height="400" loading="lazy">
<em>Visualizing Kafka’s event streaming Architecture</em></p>
<h2 id="heading-how-to-set-up-the-project-workspace">How to Set Up the Project Workspace 👨‍💻👩‍💻</h2>
<p>Enough theory for now! Let’s get our hands dirty with the actual project.</p>
<p>Assuming that you have Docker and Go installed on your machine, let’s create a directory for the project named <code>kafka-notify</code><em>.</em> Then, you will pull <a target="_blank" href="https://hub.docker.com/r/bitnami/kafka/"><strong>Bitnami’s Kafka Docker image</strong></a> for the Kafka setup, providing a hassle-free installation:</p>
<pre><code class="lang-bash">mkdir kafka-notify &amp;&amp; <span class="hljs-built_in">cd</span> kafka-notify

curl -sSL \
https://raw.githubusercontent.com/bitnami/containers/main/bitnami/kafka/docker-compose.yml &gt; docker-compose.yml
</code></pre>
<p>Before starting the Kafka broker, there’s a slight modification required in the docker-compose.yml file. Find the following string:</p>
<pre><code class="lang-yaml"><span class="hljs-string">KAFKA_CFG_ADVERTISED_LISTENERS=PLAINTEXT://:9092</span>
</code></pre>
<p>And replace it with:</p>
<pre><code class="lang-yaml"><span class="hljs-string">KAFKA_CFG_ADVERTISED_LISTENERS=PLAINTEXT://localhost:9092</span>
</code></pre>
<p>The above change ensures Kafka advertises its listener on <code>localhost</code>, which allows our local Go application to connect seamlessly. Now, you can start the Kafka broker via the following Docker command:</p>
<pre><code class="lang-bash">docker-compose up -d
</code></pre>
<p>Next, you’ll need to create a few directories to organize the project files. The <code>cmd/producer</code> and <code>cmd/consumer</code> directories will contain the main application files, and the <code>pkg/models</code> directory will store the model declarations:</p>
<pre><code class="lang-bash">mkdir -p cmd/producer cmd/consumer pkg/models
</code></pre>
<p>The last step is to initialize Go modules and install external packages. You’ll be using <code>sarama</code> to establish a connection with the Kafka broker and <code>gin</code> to handle the API endpoints for the notification system:</p>
<pre><code class="lang-bash">go mod init kafka-notify
go get github.com/IBM/sarama github.com/gin-gonic/gin
</code></pre>
<h2 id="heading-how-to-create-the-user-and-notification-models">How to Create the User and Notification Models</h2>
<p>With the workspace set up, the first step is to create the <code>User</code> and <code>Notification</code> structs. Move to the <code>pkg/models</code> directory, then create a new file named <code>models.go</code> and declare these structs within it:</p>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> models

<span class="hljs-keyword">type</span> User <span class="hljs-keyword">struct</span> {
    ID   <span class="hljs-keyword">int</span>    <span class="hljs-string">`json:"id"`</span>
    Name <span class="hljs-keyword">string</span> <span class="hljs-string">`json:"name"`</span>
}

<span class="hljs-keyword">type</span> Notification <span class="hljs-keyword">struct</span> {
    From    User   <span class="hljs-string">`json:"from"`</span>
    To      User   <span class="hljs-string">`json:"to"`</span>
    Message <span class="hljs-keyword">string</span> <span class="hljs-string">`json:"message"`</span>
}
</code></pre>
<h2 id="heading-how-to-set-up-the-kafka-producer">How to Set Up the Kafka Producer 📤</h2>
<p>The next step is to write the code for the producer. You’ll create a simple Gin web API where a user can send a notification to another user via an HTTP POST request. This request will then “produce” (send) a message to a Kafka topic named <code>"notifications"</code>.</p>
<p>Let’s navigate to the <code>cmd/producer</code> directory and create a new file named <code>producer.go</code>. Within it, you’ll set up the producer logic:</p>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> main

<span class="hljs-keyword">import</span> (
    <span class="hljs-string">"encoding/json"</span>
    <span class="hljs-string">"errors"</span>
    <span class="hljs-string">"fmt"</span>
    <span class="hljs-string">"log"</span>
    <span class="hljs-string">"net/http"</span>
    <span class="hljs-string">"strconv"</span>

    <span class="hljs-string">"kafka-notify/pkg/models"</span>

    <span class="hljs-string">"github.com/IBM/sarama"</span>
    <span class="hljs-string">"github.com/gin-gonic/gin"</span>
)

<span class="hljs-keyword">const</span> (
    ProducerPort       = <span class="hljs-string">":8080"</span>
    KafkaServerAddress = <span class="hljs-string">"localhost:9092"</span>
    KafkaTopic         = <span class="hljs-string">"notifications"</span>
)

<span class="hljs-comment">// ============== HELPER FUNCTIONS ==============</span>
<span class="hljs-keyword">var</span> ErrUserNotFoundInProducer = errors.New(<span class="hljs-string">"user not found"</span>)

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">findUserByID</span><span class="hljs-params">(id <span class="hljs-keyword">int</span>, users []models.User)</span> <span class="hljs-params">(models.User, error)</span></span> {
    <span class="hljs-keyword">for</span> _, user := <span class="hljs-keyword">range</span> users {
        <span class="hljs-keyword">if</span> user.ID == id {
            <span class="hljs-keyword">return</span> user, <span class="hljs-literal">nil</span>
        }
    }
    <span class="hljs-keyword">return</span> models.User{}, ErrUserNotFoundInProducer
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">getIDFromRequest</span><span class="hljs-params">(formValue <span class="hljs-keyword">string</span>, ctx *gin.Context)</span> <span class="hljs-params">(<span class="hljs-keyword">int</span>, error)</span></span> {
    id, err := strconv.Atoi(ctx.PostForm(formValue))
    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
        <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>, fmt.Errorf(
            <span class="hljs-string">"failed to parse ID from form value %s: %w"</span>, formValue, err)
    }
    <span class="hljs-keyword">return</span> id, <span class="hljs-literal">nil</span>
}

<span class="hljs-comment">// ============== KAFKA RELATED FUNCTIONS ==============</span>
<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">sendKafkaMessage</span><span class="hljs-params">(producer sarama.SyncProducer,
    users []models.User, ctx *gin.Context, fromID, toID <span class="hljs-keyword">int</span>)</span> <span class="hljs-title">error</span></span> {
    message := ctx.PostForm(<span class="hljs-string">"message"</span>)

    fromUser, err := findUserByID(fromID, users)
    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
        <span class="hljs-keyword">return</span> err
    }

    toUser, err := findUserByID(toID, users)
    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
        <span class="hljs-keyword">return</span> err
    }

    notification := models.Notification{
        From: fromUser,
        To:   toUser, Message: message,
    }

    notificationJSON, err := json.Marshal(notification)
    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
        <span class="hljs-keyword">return</span> fmt.Errorf(<span class="hljs-string">"failed to marshal notification: %w"</span>, err)
    }

    msg := &amp;sarama.ProducerMessage{
        Topic: KafkaTopic,
        Key:   sarama.StringEncoder(strconv.Itoa(toUser.ID)),
        Value: sarama.StringEncoder(notificationJSON),
    }

    _, _, err = producer.SendMessage(msg)
    <span class="hljs-keyword">return</span> err
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">sendMessageHandler</span><span class="hljs-params">(producer sarama.SyncProducer,
    users []models.User)</span> <span class="hljs-title">gin</span>.<span class="hljs-title">HandlerFunc</span></span> {
    <span class="hljs-keyword">return</span> <span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">(ctx *gin.Context)</span></span> {
        fromID, err := getIDFromRequest(<span class="hljs-string">"fromID"</span>, ctx)
        <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
            ctx.JSON(http.StatusBadRequest, gin.H{<span class="hljs-string">"message"</span>: err.Error()})
            <span class="hljs-keyword">return</span>
        }

        toID, err := getIDFromRequest(<span class="hljs-string">"toID"</span>, ctx)
        <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
            ctx.JSON(http.StatusBadRequest, gin.H{<span class="hljs-string">"message"</span>: err.Error()})
            <span class="hljs-keyword">return</span>
        }

        err = sendKafkaMessage(producer, users, ctx, fromID, toID)
        <span class="hljs-keyword">if</span> errors.Is(err, ErrUserNotFoundInProducer) {
            ctx.JSON(http.StatusNotFound, gin.H{<span class="hljs-string">"message"</span>: <span class="hljs-string">"User not found"</span>})
            <span class="hljs-keyword">return</span>
        }
        <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
            ctx.JSON(http.StatusInternalServerError, gin.H{
                <span class="hljs-string">"message"</span>: err.Error(),
            })
            <span class="hljs-keyword">return</span>
        }

        ctx.JSON(http.StatusOK, gin.H{
            <span class="hljs-string">"message"</span>: <span class="hljs-string">"Notification sent successfully!"</span>,
        })
    }
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">setupProducer</span><span class="hljs-params">()</span> <span class="hljs-params">(sarama.SyncProducer, error)</span></span> {
    config := sarama.NewConfig()
    config.Producer.Return.Successes = <span class="hljs-literal">true</span>
    producer, err := sarama.NewSyncProducer([]<span class="hljs-keyword">string</span>{KafkaServerAddress},
        config)
    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
        <span class="hljs-keyword">return</span> <span class="hljs-literal">nil</span>, fmt.Errorf(<span class="hljs-string">"failed to setup producer: %w"</span>, err)
    }
    <span class="hljs-keyword">return</span> producer, <span class="hljs-literal">nil</span>
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    users := []models.User{
        {ID: <span class="hljs-number">1</span>, Name: <span class="hljs-string">"Emma"</span>},
        {ID: <span class="hljs-number">2</span>, Name: <span class="hljs-string">"Bruno"</span>},
        {ID: <span class="hljs-number">3</span>, Name: <span class="hljs-string">"Rick"</span>},
        {ID: <span class="hljs-number">4</span>, Name: <span class="hljs-string">"Lena"</span>},
    }

    producer, err := setupProducer()
    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
        log.Fatalf(<span class="hljs-string">"failed to initialize producer: %v"</span>, err)
    }
    <span class="hljs-keyword">defer</span> producer.Close()

    gin.SetMode(gin.ReleaseMode)
    router := gin.Default()
    router.POST(<span class="hljs-string">"/send"</span>, sendMessageHandler(producer, users))

    fmt.Printf(<span class="hljs-string">"Kafka PRODUCER 📨 started at http://localhost%s\n"</span>,
        ProducerPort)

    <span class="hljs-keyword">if</span> err := router.Run(ProducerPort); err != <span class="hljs-literal">nil</span> {
        log.Printf(<span class="hljs-string">"failed to run the server: %v"</span>, err)
    }
}
</code></pre>
<p>Let’s break down the Kafka-related components within <code>producer.go</code>:</p>
<p>Within the <code>**setupProducer()**</code> function:</p>
<ul>
<li><code>config := sarama.NewConfig()</code>: Initializes a new default configuration for Kafka. Think of it as setting up the parameters before connecting to the broker.</li>
<li><code>config.Producer.Return.Successes = true</code>: Ensures that the producer receives an acknowledgment once the message is successfully stored in the <code>"notifications"</code> topic.</li>
<li><code>producer, err := sarama.NewSyncProducer(…)</code>: Initializes a synchronous Kafka producer that connects to the Kafka broker running at <code>localhost:9092</code>.</li>
</ul>
<p>Inside the <code>**sendKafkaMessage()**</code> function:</p>
<ul>
<li>This function starts by retrieving the <code>message</code> from the context and then attempts to find both the sender and the recipient using their IDs.</li>
<li><code>notification := models.Notification{…}</code>: Initializes a <code>Notification</code> struct that encapsulates information about the sender, the recipient, and the actual message.</li>
<li><code>msg := &amp;sarama.ProducerMessage{…}</code>: Constructs a <code>ProducerMessage</code> for the <code>"notifications"</code> topic, setting the recipient’s ID as the <code>Key</code> and the message content, which is the serialized form of the <code>Notification</code> as the <code>Value</code>.</li>
<li><code>producer.SendMessage(msg)</code>: Sends the constructed message to the <code>"notifications"</code> topic.</li>
</ul>
<p>In the <code>**sendMessageHandler()**</code> function:</p>
<ul>
<li>This function serves as an endpoint handler for the <code>/send</code> POST request. It processes the incoming request to ensure valid sender and recipient IDs are provided.</li>
<li>After fetching the IDs, it invokes the <code>sendKafkaMessage()</code> function to send the Kafka message. Depending on the result, it dispatches appropriate HTTP responses: a <code>404 Not Found</code> for nonexistent users, a <code>400 Bad Request</code> for invalid IDs, and a <code>500 Internal Server Error</code> for other failures, along with a specific error message.</li>
</ul>
<p>Finally, within the <code>**main()**</code> function:</p>
<ul>
<li>You initialize a Kafka producer via the <code>setupProducer()</code> function.</li>
<li>Then, you create a Gin <code>router</code> via <code>gin.Default()</code>, setting up a web server. Next, you define a POST endpoint <code>/send</code> to handle notifications. This endpoint expects the sender and recipient’s IDs and the message content.</li>
<li>The notification is processed upon receiving a POST request via the <code>sendMessageHandler()</code> function, and an appropriate HTTP response is dispatched.</li>
</ul>
<p>The above setup provides a simple way to simulate users sending notifications to each other and showcases how these notifications are produced to the <code>"notifications"</code> topic.</p>
<h2 id="heading-how-to-set-up-the-kafka-consumer">How to Set Up the Kafka Consumer 📥</h2>
<p>After creating the producer, the next step is to set up a consumer that listens to the <code>"notifications"</code> topic and provides an endpoint to list notifications for a specific user.</p>
<p>Let’s move to the <code>cmd/consumer</code> directory and create a new file named <code>consumer.go</code>. Within it, you’ll set up the consumer logic and the Gin-based API:</p>
<pre><code class="lang-go"><span class="hljs-keyword">package</span> main

<span class="hljs-keyword">import</span> (
    <span class="hljs-string">"context"</span>
    <span class="hljs-string">"encoding/json"</span>
    <span class="hljs-string">"errors"</span>
    <span class="hljs-string">"fmt"</span>
    <span class="hljs-string">"log"</span>
    <span class="hljs-string">"net/http"</span>
    <span class="hljs-string">"sync"</span>

    <span class="hljs-string">"kafka-notify/pkg/models"</span>

    <span class="hljs-string">"github.com/IBM/sarama"</span>
    <span class="hljs-string">"github.com/gin-gonic/gin"</span>
)

<span class="hljs-keyword">const</span> (
    ConsumerGroup      = <span class="hljs-string">"notifications-group"</span>
    ConsumerTopic      = <span class="hljs-string">"notifications"</span>
    ConsumerPort       = <span class="hljs-string">":8081"</span>
    KafkaServerAddress = <span class="hljs-string">"localhost:9092"</span>
)

<span class="hljs-comment">// ============== HELPER FUNCTIONS ==============</span>
<span class="hljs-keyword">var</span> ErrNoMessagesFound = errors.New(<span class="hljs-string">"no messages found"</span>)

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">getUserIDFromRequest</span><span class="hljs-params">(ctx *gin.Context)</span> <span class="hljs-params">(<span class="hljs-keyword">string</span>, error)</span></span> {
    userID := ctx.Param(<span class="hljs-string">"userID"</span>)
    <span class="hljs-keyword">if</span> userID == <span class="hljs-string">""</span> {
        <span class="hljs-keyword">return</span> <span class="hljs-string">""</span>, ErrNoMessagesFound
    }
    <span class="hljs-keyword">return</span> userID, <span class="hljs-literal">nil</span>
}

<span class="hljs-comment">// ====== NOTIFICATION STORAGE ======</span>
<span class="hljs-keyword">type</span> UserNotifications <span class="hljs-keyword">map</span>[<span class="hljs-keyword">string</span>][]models.Notification

<span class="hljs-keyword">type</span> NotificationStore <span class="hljs-keyword">struct</span> {
    data UserNotifications
    mu   sync.RWMutex
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-params">(ns *NotificationStore)</span> <span class="hljs-title">Add</span><span class="hljs-params">(userID <span class="hljs-keyword">string</span>,
    notification models.Notification)</span></span> {
    ns.mu.Lock()
    <span class="hljs-keyword">defer</span> ns.mu.Unlock()
    ns.data[userID] = <span class="hljs-built_in">append</span>(ns.data[userID], notification)
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-params">(ns *NotificationStore)</span> <span class="hljs-title">Get</span><span class="hljs-params">(userID <span class="hljs-keyword">string</span>)</span> []<span class="hljs-title">models</span>.<span class="hljs-title">Notification</span></span> {
    ns.mu.RLock()
    <span class="hljs-keyword">defer</span> ns.mu.RUnlock()
    <span class="hljs-keyword">return</span> ns.data[userID]
}

<span class="hljs-comment">// ============== KAFKA RELATED FUNCTIONS ==============</span>
<span class="hljs-keyword">type</span> Consumer <span class="hljs-keyword">struct</span> {
    store *NotificationStore
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-params">(*Consumer)</span> <span class="hljs-title">Setup</span><span class="hljs-params">(sarama.ConsumerGroupSession)</span> <span class="hljs-title">error</span></span>   { <span class="hljs-keyword">return</span> <span class="hljs-literal">nil</span> }
<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-params">(*Consumer)</span> <span class="hljs-title">Cleanup</span><span class="hljs-params">(sarama.ConsumerGroupSession)</span> <span class="hljs-title">error</span></span> { <span class="hljs-keyword">return</span> <span class="hljs-literal">nil</span> }

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-params">(consumer *Consumer)</span> <span class="hljs-title">ConsumeClaim</span><span class="hljs-params">(
    sess sarama.ConsumerGroupSession, claim sarama.ConsumerGroupClaim)</span> <span class="hljs-title">error</span></span> {
    <span class="hljs-keyword">for</span> msg := <span class="hljs-keyword">range</span> claim.Messages() {
        userID := <span class="hljs-keyword">string</span>(msg.Key)
        <span class="hljs-keyword">var</span> notification models.Notification
        err := json.Unmarshal(msg.Value, &amp;notification)
        <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
            log.Printf(<span class="hljs-string">"failed to unmarshal notification: %v"</span>, err)
            <span class="hljs-keyword">continue</span>
        }
        consumer.store.Add(userID, notification)
        sess.MarkMessage(msg, <span class="hljs-string">""</span>)
    }
    <span class="hljs-keyword">return</span> <span class="hljs-literal">nil</span>
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">initializeConsumerGroup</span><span class="hljs-params">()</span> <span class="hljs-params">(sarama.ConsumerGroup, error)</span></span> {
    config := sarama.NewConfig()

    consumerGroup, err := sarama.NewConsumerGroup(
        []<span class="hljs-keyword">string</span>{KafkaServerAddress}, ConsumerGroup, config)
    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
        <span class="hljs-keyword">return</span> <span class="hljs-literal">nil</span>, fmt.Errorf(<span class="hljs-string">"failed to initialize consumer group: %w"</span>, err)
    }

    <span class="hljs-keyword">return</span> consumerGroup, <span class="hljs-literal">nil</span>
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">setupConsumerGroup</span><span class="hljs-params">(ctx context.Context, store *NotificationStore)</span></span> {
    consumerGroup, err := initializeConsumerGroup()
    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
        log.Printf(<span class="hljs-string">"initialization error: %v"</span>, err)
    }
    <span class="hljs-keyword">defer</span> consumerGroup.Close()

    consumer := &amp;Consumer{
        store: store,
    }

    <span class="hljs-keyword">for</span> {
        err = consumerGroup.Consume(ctx, []<span class="hljs-keyword">string</span>{ConsumerTopic}, consumer)
        <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
            log.Printf(<span class="hljs-string">"error from consumer: %v"</span>, err)
        }
        <span class="hljs-keyword">if</span> ctx.Err() != <span class="hljs-literal">nil</span> {
            <span class="hljs-keyword">return</span>
        }
    }
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">handleNotifications</span><span class="hljs-params">(ctx *gin.Context, store *NotificationStore)</span></span> {
    userID, err := getUserIDFromRequest(ctx)
    <span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {
        ctx.JSON(http.StatusNotFound, gin.H{<span class="hljs-string">"message"</span>: err.Error()})
        <span class="hljs-keyword">return</span>
    }

    notes := store.Get(userID)
    <span class="hljs-keyword">if</span> <span class="hljs-built_in">len</span>(notes) == <span class="hljs-number">0</span> {
        ctx.JSON(http.StatusOK,
            gin.H{
                <span class="hljs-string">"message"</span>:       <span class="hljs-string">"No notifications found for user"</span>,
                <span class="hljs-string">"notifications"</span>: []models.Notification{},
            })
        <span class="hljs-keyword">return</span>
    }

    ctx.JSON(http.StatusOK, gin.H{<span class="hljs-string">"notifications"</span>: notes})
}

<span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {
    store := &amp;NotificationStore{
        data: <span class="hljs-built_in">make</span>(UserNotifications),
    }

    ctx, cancel := context.WithCancel(context.Background())
    <span class="hljs-keyword">go</span> setupConsumerGroup(ctx, store)
    <span class="hljs-keyword">defer</span> cancel()

    gin.SetMode(gin.ReleaseMode)
    router := gin.Default()
    router.GET(<span class="hljs-string">"/notifications/:userID"</span>, <span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">(ctx *gin.Context)</span></span> {
        handleNotifications(ctx, store)
    })

    fmt.Printf(<span class="hljs-string">"Kafka CONSUMER (Group: %s) 👥📥 "</span>+
        <span class="hljs-string">"started at http://localhost%s\n"</span>, ConsumerGroup, ConsumerPort)

    <span class="hljs-keyword">if</span> err := router.Run(ConsumerPort); err != <span class="hljs-literal">nil</span> {
        log.Printf(<span class="hljs-string">"failed to run the server: %v"</span>, err)
    }
}
</code></pre>
<p>Let’s examine the Kafka-related operations within <code>consumer.go</code>:</p>
<p>Within the <code>**initializeConsumerGroup()**</code> function:</p>
<ul>
<li><code>config := sarama.NewConfig()</code>: Initializes a new default configuration for Kafka.</li>
<li><code>consumerGroup, err := sarama.NewConsumerGroup(…)</code>: Creates a new Kafka consumer group that connects to the broker running on <code>localhost:9092</code>. The group name is <code>"notifications-group"</code>.</li>
</ul>
<p>Inside the <code>**Consumer**</code> struct and its methods:</p>
<ul>
<li>The <code>Consumer</code> struct has a <code>store</code> field, which is a reference to the <code>NotificationStore</code> to keep track of the received notifications.</li>
<li><code>Setup()</code> and <code>Cleanup()</code> methods are required to satisfy the <code>sarama.ConsumerGroupHandler</code>  interface. While they will NOT be used in this tutorial, they can serve  potential roles for initialization and cleanup during message consumption but act as placeholders here.</li>
<li>In the <code>ConsumeClaim()</code> method: The consumer listens for new messages on the topic. For each message, it fetches the <code>userID</code> (the <code>Key</code> of the message), un-marshals the message into a <code>Notification</code> struct, and adds the notification to the <code>NotificationStore</code>.</li>
</ul>
<p>In the <code>**setupConsumerGroup()**</code> function:</p>
<ul>
<li>This function sets up the Kafka consumer group, listens for incoming messages, and processes them using the <code>Consumer</code> struct methods.</li>
<li>It runs a <code>for</code> loop indefinitely, consuming messages from the <code>“notifications”</code> topic and processing any errors that arise.</li>
</ul>
<p>The <code>**handleNotifications()**</code> function:</p>
<ul>
<li>Initially, it attempts to retrieve the <code>userID</code> from the request. If it doesn’t exist, it returns a <code>404 Not Found</code> status.</li>
<li>Then, it fetches the notifications for the provided user ID from the <code>NotificationStore</code>.  Depending on whether the user has notifications, it responds with a <code>200 OK</code> status and either an empty notifications slice or sends back the current notifications.</li>
</ul>
<p>Lastly, within the <code>**main()**</code> function:</p>
<ul>
<li><code>store := &amp;NotificationStore{…}</code>: Creates an instance of <code>NotificationStore</code> to hold the notifications</li>
<li><code>ctx, cancel := context.WithCancel(context.Background())</code>: Sets up a cancellable context that can be used to stop the consumer group.</li>
<li><code>go setupConsumerGroup(ctx, store)</code>: Starts the consumer group in a separate Goroutine, allowing it to operate concurrently without blocking the main thread.</li>
<li>The last step is to create a Gin <code>router</code> and define a GET endpoint <code>/notifications/:userID</code> that will fetch the notifications for a specific user via the <code>handleNotifications()</code> function when accessed.</li>
</ul>
<p>This setup provides a straightforward way to consume messages from the <code>"notifications"</code> topic and present them to users through a web endpoint.</p>
<h2 id="heading-lets-test-the-real-time-notification-system">Let's Test the Real-Time Notification System👨‍🔬🖥️👩‍🔬</h2>
<p>Now that the producer and consumer are ready, it’s time to see the system in action.</p>
<h3 id="heading-1-start-the-producer">1. Start the producer</h3>
<p>Open up a terminal, move into the <code>kafka-notify</code> directory, and run the producer with the following command:</p>
<pre><code class="lang-bash">go run cmd/producer/producer.go
</code></pre>
<h3 id="heading-2-start-the-consumer">2. Start the consumer</h3>
<p>Open up a second terminal window, navigate to the <code>kafka-notify</code> directory, and start the consumer by running:</p>
<pre><code class="lang-bash">go run cmd/consumer/consumer.go
</code></pre>
<h3 id="heading-3-sending-notifications">3. Sending notifications</h3>
<p>With both producer and consumer running, you can simulate sending notifications. Open up a third terminal and use the below <code>curl</code> commands to send notifications:</p>
<p><strong>User 1 (Emma) receives a notification from User 2 (Bruno):</strong></p>
<pre><code class="lang-bash">curl -X POST http://localhost:8080/send \
-d <span class="hljs-string">"fromID=2&amp;toID=1&amp;message=Bruno started following you."</span>
</code></pre>
<p><strong>User 2 (Bruno) receives a notification from User 1 (Emma):</strong></p>
<pre><code class="lang-bash">curl -X POST http://localhost:8080/send \
-d <span class="hljs-string">"fromID=1&amp;toID=2&amp;message=Emma mentioned you in a comment: 'Great seeing you yesterday, @Bruno!'"</span>
</code></pre>
<p><strong>User 1 (Emma) receives a notification from User 4 (Lena):</strong></p>
<pre><code class="lang-bash">curl -X POST http://localhost:8080/send \
-d <span class="hljs-string">"fromID=4&amp;toID=1&amp;message=Lena liked your post: 'My weekend getaway!'"</span>
</code></pre>
<h3 id="heading-4-retrieving-notifications">4. Retrieving notifications</h3>
<p>Finally, you can fetch the notifications of a specific user. You can use the below <code>curl</code> commands to fetch notifications:</p>
<p><strong>Retrieving notifications for User 1 (Emma):</strong></p>
<pre><code class="lang-bash">curl http://localhost:8081/notifications/1
</code></pre>
<p><strong>Output:</strong></p>
<pre><code class="lang-json">{<span class="hljs-attr">"notifications"</span>: [{<span class="hljs-attr">"from"</span>: {<span class="hljs-attr">"id"</span>: <span class="hljs-number">2</span>, <span class="hljs-attr">"name"</span>: <span class="hljs-string">"Bruno"</span>}, <span class="hljs-attr">"to"</span>: {<span class="hljs-attr">"id"</span>: <span class="hljs-number">1</span>, <span class="hljs-attr">"name"</span>: <span class="hljs-string">"Emma"</span>}, <span class="hljs-attr">"message"</span>: <span class="hljs-string">"Bruno started following you."</span>}]}
{<span class="hljs-attr">"notifications"</span>: [{<span class="hljs-attr">"from"</span>: {<span class="hljs-attr">"id"</span>: <span class="hljs-number">4</span>, <span class="hljs-attr">"name"</span>: <span class="hljs-string">"Lena"</span>}, <span class="hljs-attr">"to"</span>: {<span class="hljs-attr">"id"</span>: <span class="hljs-number">1</span>, <span class="hljs-attr">"name"</span>: <span class="hljs-string">"Emma"</span>}, <span class="hljs-attr">"message"</span>: <span class="hljs-string">"Lena liked your post: 'My weekend getaway!'"</span>}]}
</code></pre>
<p>In the above output, you see a <code>JSON</code> response listing all the notifications for <strong>Emma</strong>. As you send more notifications, they accumulate, and you can fetch them using the consumer’s API.</p>
<h2 id="heading-wrapping-up">Wrapping up 📝</h2>
<p>In this tutorial, you’ve learned how to set up a basic real-time notification system using Kafka in Go. </p>
<p>By simulating the process of users sending and fetching notifications, you’ve gained hands-on experience with Kafka components. This is a foundational step in understanding how Kafka can be integrated into Go applications for various real-time data processing tasks.</p>
<p>You can access the entire codebase for this project in the following GitHub repository: <a target="_blank" href="https://github.com/gutyoh/kafka-notify">https://github.com/gutyoh/kafka-notify</a></p>
<p>If you found this article helpful and want to expand your knowledge on Golang 🐿️, Docker 🐳, and Gin 🍸, consider checking out the <strong><a target="_blank" href="https://hyperskill.org/tracks/25?category=12&amp;utm_source=fc_hs&amp;utm_medium=social&amp;utm_campaign=hermann">Introduction to Go track</a></strong>, which covers basic Golang concepts. </p>
<p>Registered users can also check the <strong><a target="_blank" href="https://hyperskill.org/tracks/43?category=20&amp;utm_source=fc_hs&amp;utm_medium=social&amp;utm_campaign=hermann">Go Developer</a></strong> and <strong><a target="_blank" href="https://hyperskill.org/tracks/64?category=20&amp;utm_source=fc_hs&amp;utm_medium=social&amp;utm_campaign=hermann">Introduction to Docker</a></strong> tracks on Hyperskill. I've been actively involved as an expert in curating these tracks, ensuring they deliver top-notch educational content.</p>
<p>Before concluding, I owe a big thank you to my dear friend <strong>Anton Illarionov</strong>. His expertise in integrating Go with Kafka inspired the idea for this article. You can explore his projects on <a target="_blank" href="https://github.com/ant1k9">GitHub</a>.</p>
<p>Let me know if you have any questions or feedback regarding this article.</p>
<p>Thank you for reading, and keep on coding!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Create Multiple Virtual Hosts on a Single RabbitMQ Instance ]]>
                </title>
                <description>
                    <![CDATA[ By Ridwan Yusuf Hi, friends, and welcome to another tutorial. We'll be talking about RabbitMQ, a tool that is widely used as a message broker in distributed and Pub-Sub systems.  While multiple applications can share a single RabbitMQ instance, it's ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-create-multiple-virtual-hosts-on-one-rabbitmq-instance/</link>
                <guid isPermaLink="false">66d460c5d7a4e35e384349a7</guid>
                
                    <category>
                        <![CDATA[ distributed systems ]]>
                    </category>
                
                    <category>
                        <![CDATA[ message broker ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Python ]]>
                    </category>
                
                    <category>
                        <![CDATA[ rabbitmq ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Wed, 26 Jul 2023 21:25:15 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/07/Untitled-design.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Ridwan Yusuf</p>
<p>Hi, friends, and welcome to another tutorial. We'll be talking about RabbitMQ, a tool that is widely used as a message broker in distributed and Pub-Sub systems. </p>
<p>While multiple applications can share a single RabbitMQ instance, it's a great approach to configure it to have different virtual hosts for each application. </p>
<p>One practical usage in a Python application is using it as a Celery broker URL or simply as a message queue.</p>
<p>One benefit of this is that it saves the costs that comes with spinning up multiple instances of RabbitMQ. Creating RabbitMQ virtual hosts is similar both locally and when running in a self-managed solution such as AWS RabbitMQ</p>
<p>By the end of this guide, you will be able to:</p>
<ol>
<li>Create multiple virtual hosts for a single RabbitMQ instance.</li>
<li>Test the connections using the correct credentials, that is user, password, and virtual host.</li>
</ol>
<p><strong>Prerequisites to follow along</strong>:</p>
<ol>
<li>Ensure you have Docker and Docker Compose installed, or</li>
<li>Have a self-managed RabbitMQ instance from AWS, CloudAMQP, or any other service provider</li>
</ol>
<p>Without any delay, let’s get started</p>
<h2 id="heading-how-to-run-a-rabbitmq-instance-locally">How to Run a RabbitMQ Instance Locally</h2>
<p>To keep things simple, we are going to run the RabbitMQ instance in a Docker container.</p>
<p>Create a file named docker-compose.yml and update it with the following content:</p>
<p><em>docker-compose.yml</em></p>
<pre><code class="lang-yaml"><span class="hljs-attr">version:</span> <span class="hljs-string">"3.8"</span>
<span class="hljs-attr">services:</span>
  <span class="hljs-attr">rabbitmq:</span>
    <span class="hljs-attr">image:</span> <span class="hljs-string">rabbitmq:3.8-management-alpine</span>
    <span class="hljs-attr">container_name:</span> <span class="hljs-string">'rabbitmq_test'</span>
    <span class="hljs-attr">environment:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">RABBITMQ_DEFAULT_USER=sampleuser</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">RABBITMQ_DEFAULT_PASS=samplepassword</span>
    <span class="hljs-attr">ports:</span>
        <span class="hljs-bullet">-</span> <span class="hljs-number">5672</span><span class="hljs-string">:5672</span>
        <span class="hljs-bullet">-</span> <span class="hljs-number">15672</span><span class="hljs-string">:15672</span>
    <span class="hljs-attr">volumes:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">~/.docker-conf/rabbitmq/data/:/var/lib/rabbitmq/</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">~/.docker-conf/rabbitmq/log/:/var/log/rabbitmq</span>
</code></pre>
<p>To start the container, run this command in the terminal:</p>
<pre><code class="lang-yaml"><span class="hljs-string">docker-compose</span> <span class="hljs-string">up</span>
</code></pre>
<p>Once the container is up and running, access the GUI by visiting this link: <a target="_blank" href="http://localhost:15672/">http://localhost:15672/</a></p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/07/ezgif-2-5cc0fa8243.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>RabbitMQ GUI login page</em></p>
<p>Use the credentials specified in the docker-compose file to gain access to the dashboard – “sampleuser” and “samplepassword” in my case.</p>
<p><strong>Note:</strong> If you are using a self-managed RabbitMQ instance from AWS or CloudAMQP, the RabbitMQ connection string will look similar to this:</p>
<p>amqps://ausername:<a target="_blank" href="mailto:apassword@32wewjijiokkoo.mq.eu-west-3.amazonaws.com">apassword@32wewjijiokkoo.mq.eu-west-3.amazonaws.com</a>:5671</p>
<p>To access the RabbitMQ admin dashboard, follow these steps:</p>
<ol>
<li>Visit the URL using the HTTPS protocol: <a target="_blank" href="https://32wewjijiokkoo.mq.eu-west-3.amazonaws.com">https://32wewjijiokkoo.mq.eu-west-3.amazonaws.com</a></li>
<li>Remove the username, password, and port from the URL.</li>
<li>After accessing the URL, the system will prompt you to enter the username and password specified in the RabbitMQ connection string (“ausername” and “apassword” in this case). Provide these credentials to log in to the admin dashboard.</li>
</ol>
<h2 id="heading-how-to-create-a-virtual-host">How to Create a Virtual Host</h2>
<p>Once you are logged in, click on the ‘Admin’ tab, and then navigate to the ‘Virtual Hosts’ tab as shown in the image below.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/07/ezgif-4-82232fd2b0.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>RabbitMQ Virtualhost tab</em></p>
<p>Click on ‘Add a new virtual host’, and provide it with an appropriate name. Finally, click on the ‘Add virtual host’ button to create the new virtual host.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/07/ezgif-4-26e9083f62.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>New Virtual Host created</em></p>
<h2 id="heading-how-to-create-a-new-user">How to Create a New User</h2>
<p>On the Users tab, click on the ‘Add a user’ toggle. Specify a Username and Password for the new user. If you wish, you may grant the user access to the Admin (GUI) interface. Finally, click on the ‘Add user’ button to create the new user.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/07/ezgif-4-e787f0c102.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>Create a new user</em></p>
<h2 id="heading-how-to-assign-the-new-user-to-the-created-virtual-host-vhost">How to Assign the New User to the Created Virtual Host (Vhost)</h2>
<p>On the Users tab, locate and click on the previously created user, which was named ‘user1’ in my case.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/07/ezgif-4-cb6b620bdf.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>New user in users list</em></p>
<p>For the new user, choose the virtual host as ‘new-virtual-host’, and then click the ‘Set permission’ button. This grants the user access to the specified virtual host. To confirm this, go back to the Users tab and verify that the user now appears with access to the ‘new-virtual-host'</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/07/WhatsApp-Image-2023-07-25-at-19.59.44.jpeg" alt="Image" width="600" height="400" loading="lazy">
<em>Assign new user to the created virtual host</em></p>
<p>By now, the new user 'user1' has been configured to access the vhost 'new-virtual-host'.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/07/Screenshot-from-2023-07-26-06-22-12.png" alt="Image" width="600" height="400" loading="lazy">
<em>New user assigned to the created virtual host</em></p>
<h2 id="heading-how-to-test-the-connection-for-the-new-user-and-vhost">How to Test the Connection for the New User and Vhost</h2>
<p>To test if the new user can access the new vhost, you can use the following sample Python script. Once everything is working correctly, you can use the URL string to connect to the RabbitMQ broker in any application.</p>
<p>_test<em>rabbit.py</em></p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> pika

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">test_rabbitmq_url</span>(<span class="hljs-params">url</span>):</span>

    <span class="hljs-keyword">try</span>:
        params = pika.URLParameters(url)
        connection = pika.BlockingConnection(params)
        connection.close()
        print(<span class="hljs-string">"Connection successful!"</span>)

    <span class="hljs-keyword">except</span> pika.exceptions.AMQPError <span class="hljs-keyword">as</span> e:
        print(<span class="hljs-string">"Connection failed:"</span>, e)

test_rabbitmq_url(<span class="hljs-string">'amqp://user1:password@localhost:5672/new-virtual-host'</span>)
</code></pre>
<p>Note how we have specified the RabbitMQ URL: it has the username as “user1” and password as “password9,” while the virtual host is named ‘new-virtual-host.’</p>
<p>Remember to install pika by running <code>pip install pika</code> on the command line.</p>
<p>To run this script on the terminal, enter the following command:</p>
<pre><code class="lang-bash">python test_rabbit.py
</code></pre>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/07/ezgif-4-4dda3c97ef.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>Successfully connected to RabbitMQ</em></p>
<p>This indicates a successful connection to the RabbitMQ instance.</p>
<p>Change the password in the utility function to an incorrect one, and you should see an outcome similar to this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/07/ezgif-4-85582a7c7f.jpg" alt="Image" width="600" height="400" loading="lazy">
<em>Connection to RabbitMQ failed</em></p>
<h2 id="heading-wrapping-up">Wrapping Up</h2>
<p>In conclusion, creating multiple virtual hosts on a single RabbitMQ instance can significantly enhance your message queue management capabilities. </p>
<p>By effectively segregating applications and resources, you ensure better organization, security, and scalability. With the step-by-step guide provided in this article, you now have the knowledge to harness the full potential of RabbitMQ</p>
<p>Thanks for reading, and I hope you enjoyed the article.</p>
<p>For more interesting content and tips, please feel free to check out my video collection on <a target="_blank" href="https://www.youtube.com/@ridwanray">YouTube</a> and consider hitting the subscribe button.</p>
<p>You can also find me on <a target="_blank" href="https://linkedin.com/in/ridwan-yusufa/">LinkedIn</a>.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Use RabbitMQ with NodeJS to Send and Receive Messages ]]>
                </title>
                <description>
                    <![CDATA[ If you're exploring the world of distributed systems and real-time data pipelines, you've probably come across the concept of message queues.  There are a number of tools in this field, but RabbitMQ and Apache Kafka are two of the most popular. While... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-use-rabbitmq-with-nodejs/</link>
                <guid isPermaLink="false">66ba10e0052fa53219e0a37a</guid>
                
                    <category>
                        <![CDATA[ message broker ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Node.js ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Arunachalam B ]]>
                </dc:creator>
                <pubDate>Tue, 23 May 2023 14:45:51 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/05/What-is-RabbitMQ-and-How-to-use-it-with-NodeJS_1.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>If you're exploring the world of distributed systems and real-time data pipelines, you've probably come across the concept of message queues. </p>
<p>There are a number of tools in this field, but RabbitMQ and Apache Kafka are two of the most popular. While both are robust and reliable, they have unique features and use cases that make them distinct.</p>
<p>RabbitMQ is an open-source message broker. It's recognized for its flexibility and support for various messaging protocols. Apache Kafka is rapidly gaining popularity and is known for its ability to handle real-time data feeds with low latency.</p>
<p>In this tutorial, I'll focus on RabbitMQ, its core features, and how you can use it to effectively build scalable, loosely coupled applications.</p>
<p>Stay with me as we explore the world of RabbitMQ, its unique capabilities, and how it sets itself apart in the ever-evolving landscape of message queue technologies.</p>
<h2 id="heading-what-is-rabbitmq">What is RabbitMQ?</h2>
<p>RabbitMQ is an open-source message broker software (also called a message-oriented middleware) that implements the Advanced Message Queuing Protocol (AMQP). It provides a common platform for sending and receiving messages. </p>
<p>RabbitMQ supports multiple messaging protocols and can be deployed in distributed and federated configurations to meet high-scale, high-availability requirements.</p>
<h2 id="heading-when-should-you-use-rabbitmq">When Should You Use RabbitMQ?</h2>
<p>Consider an e-commerce website (like Amazon) where users can place orders that need to be processed. </p>
<p>The order processing system might involve several steps, such as inventory checks, payment processing, shipping, and so on, each of which can potentially take some time and are ideally handled asynchronously.</p>
<ol>
<li><strong>Inventory Checks:</strong> When a user places an order, the system should check whether the ordered products are in stock. You can send a message to a queue that is consumed by a service responsible for checking inventory. This way, even if the inventory service is temporarily down or overloaded, the order messages won't be lost – they'll be processed as soon as the service is available.</li>
<li><strong>Payment Processing:</strong> The payment processing might be done by another microservice. Once the inventory check is completed, a message can be sent to a queue for the payment service. This decouples the payment processing from the inventory checking, allowing these operations to scale independently.</li>
<li><strong>Shipping:</strong> After payment confirmation, a message can be sent to another queue that's responsible for handling shipping. Again, this service might take some time, but because it's decoupled from the rest of the system, it won't slow down other operations.</li>
<li><strong>Notification system:</strong> After every successful order placement, payment, and shipment, notifications (Email or SMS) must be sent to the customer. This can be handled by separate services that listen to specific queues.</li>
</ol>
<h2 id="heading-how-to-install-and-run-rabbitmq">How to Install and Run RabbitMQ</h2>
<p>In this example, I'll be showing you how to use Docker to run RabbitMQ. But if you prefer, you can install and run it manually on your system. The official <a target="_blank" href="https://www.rabbitmq.com/install-windows.html">documentation</a> provides a detailed guide on how to do this.</p>
<p>I find Docker to be a convenient tool for running RabbitMQ because it simplifies the setup and management processes. If you're new to Docker, I recommend reading my <a target="_blank" href="https://www.freecodecamp.org/news/how-to-get-started-with-docker-using-nodejs/">previous</a> tutorials related to Docker for a thorough understanding.</p>
<p>To get started, you'll need to pull the Docker image from Docker Hub.</p>
<pre><code>docker pull rabbitmq
</code></pre><p><img src="https://www.freecodecamp.org/news/content/images/2023/05/image-64.png" alt="Image" width="600" height="400" loading="lazy">
<em>Official Docker image of RabbitMQ in Docker Desktop</em></p>
<p>Before running the image, you need to map the two port numbers (15672 and 5672).</p>
<ol>
<li><strong>Port 5672</strong>: This is the default port for RabbitMQ when using AMQP (Advanced Message Queuing Protocol). Clients that connect with AMQP typically use this port. So, if you're using an AMQP client library to connect to RabbitMQ, it's likely to connect on port 5672.</li>
<li><strong>Port 15672</strong>: This is the default port for the RabbitMQ Management UI, when using the <code>rabbitmq_management</code> plugin. The Management UI is a web-based interface that allows you to monitor and control your RabbitMQ server.</li>
</ol>
<p>I'm running RabbitMQ on the Docker by adding the above-mentioned ports. Refer the below screenshot for additional reference. </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/05/image-75.png" alt="Image" width="600" height="400" loading="lazy">
<em>Port configuration to run the RabbitMQ Image.</em></p>
<p>Our RabbitMQ Server is up and running in Docker.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/05/image-66.png" alt="Image" width="600" height="400" loading="lazy">
<em>RabbitMQ Server container running in Docker</em></p>
<h2 id="heading-how-to-implement-a-message-queue-in-nodejs">How to Implement a Message Queue in NodeJS</h2>
<p>I'll using <code>amqplib</code>, which is a popular NodeJS library that provides an API for interacting with RabbitMQ. It supports all the features of RabbitMQ's AMQP 0-9-1 model, including things like confirm channels, exchanges, queues, bindings, and message properties.</p>
<p>I have been using the term AMQ Protocol in this tutorial and I feel like this is the right time to give a quick introduction to it.</p>
<h3 id="heading-what-is-amqp">What is AMQP?</h3>
<p>AMQP stands for Advanced Message Queuing Protocol. It is an open-standard protocol for message-oriented middleware. The defining features of AMQP are message orientation, queuing, routing (including point-to-point and publish-and-subscribe), reliability, and security.</p>
<p>AMQP has the following components:</p>
<ol>
<li><strong>Producer</strong> is an application that sends messages.</li>
<li><strong>Consumer</strong> is an application that receives messages.</li>
<li><strong>Queue</strong> is a buffer that stores the messages.</li>
<li><strong>Message</strong> is the information that is sent from the producer to a consumer.</li>
<li><strong>Exchange</strong> receives messages from producers and pushes them to queues depending on rules defined by the exchange type. The exchange type determines how messages are routed.</li>
<li><strong>Binding</strong> links the queue to the exchange.</li>
</ol>
<p>The AMQP protocol enables standardized communication between different applications, making it a good choice for a messaging system in a microservices architecture. This protocol can ensure that a message is delivered not just to the messaging system, but all the way to the correct consumer.</p>
<p>You'll remember the example that I described at the beginning of this article about the high level implementation of message queues in a E-commerce site.</p>
<p>Let's go through the same but a bit deeper in the RabbitMQ context.</p>
<h3 id="heading-order-placement">Order Placement</h3>
<p>When a customer places an order on the e-commerce website, the order service produces a message to a RabbitMQ exchange. The message contains information about the product ID and the quantity ordered.</p>
<h3 id="heading-inventory-update">Inventory Update</h3>
<p>An inventory service is set up as a consumer to receive messages from a queue bound to the exchange. Once it receives a message, it reduces the inventory for the specified product by the ordered quantity. If the inventory is insufficient, it can send a message back to the order service to indicate the problem.</p>
<h3 id="heading-order-confirmation">Order Confirmation</h3>
<p>Once the inventory service successfully updates the inventory, it'll send a message to the order service. The order service, set up as a consumer for this exchange, can then update the order status and notify the customer.</p>
<h2 id="heading-benefits">Benefits</h2>
<h3 id="heading-resilience">Resilience</h3>
<p>Let's assume your inventory service is down for some time. Then the messages in the RabbitMQ queue will stay there and won't be lost. Once the inventory service is back online, it'll continue processing the messages from where it left off.</p>
<h3 id="heading-scalability">Scalability</h3>
<p>During high traffic periods, more instances of the inventory service can be launched, all consuming messages from the same queue. This enables load balancing and ensures that the system can handle the increased load.</p>
<p>Let's come back to our implementation. In this example, we'll send a message from sender to our receiver. On the receiver end, we print the message on the console. </p>
<h2 id="heading-how-to-create-the-sender-producer">How to Create the Sender (Producer)</h2>
<p>This is the component or part of our application that creates and sends messages to the messaging queue. </p>
<p>The sender does not send messages directly to the consumer. Instead, it sends the messages to an exchange in RabbitMQ. The exchange then routes the messages to the appropriate queue based on certain criteria.</p>
<p>Here we're creating a queue called <code>product_inventory</code>. Alternatively, you can clone my repo from <a target="_blank" href="https://github.com/5minslearn/rabbit-sender">here</a>. </p>


<p>We can send only byte arrays in the message, So I convert the message object to a string and send it to the queue. From the above code, you can understand that we're creating a channel and sending a message through it. </p>
<h2 id="heading-how-to-create-the-receiver-consumer">How to Create the Receiver (Consumer)</h2>
<p>This is the component or part of our application that receives and processes the messages from the queue. A consumer can continuously poll the queue for new messages or be set up to automatically trigger when a new message is added to the queue.</p>
<p>Here we're listening for messages. Alternatively, you can clone my repo from <a target="_blank" href="https://github.com/5minslearn/rabbit-receiver">here</a>. </p>


<p>In the above code, we're listening for messages (<code>consume</code>) and print them on the console once we receive it. </p>
<p>In the context of our specific use case, the file containing the message sender (or producer) should typically be located in the root directory of our e-commerce site project. This is where we generate and send messages based on user actions, such as placing an order.</p>
<p>On the other hand, the file containing the message receiver (or consumer) should ideally be located in the inventory management service. This is because the inventory management service is responsible for processing these messages, such as updating the inventory when an order is placed.</p>
<p>Let's run our receiver service first:</p>
<pre><code>yarn start
</code></pre><p>The initial output of the consumer service looks like this:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/05/image-78.png" alt="Image" width="600" height="400" loading="lazy">
<em>Initial output in the consumer service - Listening for messages</em></p>
<p>Once we run our sender, a message will be sent to the consumer. Run the same command <code>yarn start</code> on the sender repo. </p>
<p>Here's the output of it:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/05/image-79.png" alt="Image" width="600" height="400" loading="lazy">
<em>Sending a message from the producer to the consumer</em></p>
<p>Hurray! We received a message sent from the RabbitMQ producer in our consumer service.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/05/image-80.png" alt="Image" width="600" height="400" loading="lazy">
<em>Received message from the RabbitMQ producer in our consumer service</em></p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In this article, we've explored the basics of RabbitMQ, a robust and efficient message broker, and demonstrated its application in a NodeJS environment. </p>
<p>Using a simple e-commerce scenario, we showcased how to set up a sender (producer) and a consumer to handle asynchronous messages between different components of our application. But in real-world applications, you will likely encounter more complex scenarios that require advanced integrations and the usage of RabbitMQ.</p>
<p>To navigate these complexities, it's crucial to have a solid understanding of RabbitMQ's underlying concepts and its AMQP protocol. As you delve deeper into RabbitMQ, you'll find it to be an incredibly versatile tool, capable of handling a wide range of messaging needs, and ultimately helping you build scalable, decoupled, and resilient applications.</p>
<p>Check out the source code of the project on GitHub: <a target="_blank" href="https://github.com/5minslearn/rabbit-sender">rabbit-sender</a>, <a target="_blank" href="https://github.com/5minslearn/rabbit-receiver">rabbit-receiver</a>. </p>
<p>To learn more about RabbitMQ, subscribe to my email newsletter on my <a target="_blank" href="https://5minslearn.gogosoon.com/?ref=fcc_rabbitmq">site</a> (<a target="_blank" href="https://5minslearn.gogosoon.com/?ref=fcc_rabbitmq">https://5minslearn.gogosoon.com</a>) and follow me on social media. </p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ An introduction to RabbitMQ, a broker that deals in messages ]]>
                </title>
                <description>
                    <![CDATA[ By Chandrabhan Singh An introduction to RabbitMQ, message broker, AMQP model and more. In distributed systems, communication between various applications plays an important role. Effectively passing messages between applications was always a crucial ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/rabbitmq-9e8f78194993/</link>
                <guid isPermaLink="false">66d45dd936c45a88f96b7cc3</guid>
                
                    <category>
                        <![CDATA[ message broker ]]>
                    </category>
                
                    <category>
                        <![CDATA[ General Programming ]]>
                    </category>
                
                    <category>
                        <![CDATA[ queue ]]>
                    </category>
                
                    <category>
                        <![CDATA[ rabbitmq ]]>
                    </category>
                
                    <category>
                        <![CDATA[ technology ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Fri, 05 Apr 2019 20:42:10 +0000</pubDate>
                <media:content url="https://cdn-media-1.freecodecamp.org/images/1*HCpBJmTd_sELllvhVOaevg.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Chandrabhan Singh</p>
<h4 id="heading-an-introduction-to-rabbitmq-message-broker-amqp-model-and-more">An introduction to RabbitMQ, message broker, AMQP model and more.</h4>
<p>In distributed systems, communication between various applications plays an important role. Effectively passing messages between applications was always a crucial decision in system design. One of the elegant solutions to pass messages around your distributed system is a message broker.</p>
<p>In distributed systems, communication between various applications plays an important role. Effectively passing messages between applications was always a crucial decision in system design. One of the elegant solutions to pass messages around your distributed system is a message broker.</p>
<p>They bring in decoupling between the applications and provide an effective way to communicate. With message brokers, an application needs no prior knowledge of their recipients to communicate.</p>
<p>However, what is RabbtiMQ? How does RabbitMQ fit in this picture? Also, what is AMQP?</p>
<p>By the end of this article, we will be able to answer these questions. I also added a few animations so that you can visualize RabbitMQ concepts.</p>
<p>So are you excited? I am! If you ever had difficulties understanding message brokers, as I did, then this article is the right place to start your journey. Stay with me ?</p>
<h1 id="heading-message-broker">Message Broker</h1>
<p>In general, a broker is a person who facilitates trades between a buyer and a seller. An example could be a real estate agent or a stockbroker.</p>
<p>Similarly, if we want to trade messages between two distributed software components, we need a mediator. This mediator is known as the message broker. It receives incoming messages from a sender and sends them to a recipient. This way the sender and receiver can be totally isolated.</p>
<p>Another analogy for a message broker can be a Post Office (see Figure 1). Let’s take a scenario where you are going to send a letter to your cousin living in another city. Then as per this analogy, you are a producer, your cousin is a consumer, and the post office is a message broker.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*nUaJxRXwLbgZyM4KWwDfig.png?q=20" alt="Image" width="48" height="24" loading="lazy">
<em>Figure 1: Analogy for message broker</em></p>
<h1 id="heading-rabbitmq-as-message-broker">RabbitMQ as message broker</h1>
<p>Now we know that the purpose of a message broker is to route messages from a producer to a consumer. Let’s examine one such message broker — RabbitMQ. It’s one of the most extensively used message brokers these days.</p>
<p>The way RabbitMQ routes messages depends upon the messaging protocol it implements. RabbitMQ supports multiple messaging protocols. However, the one we are interested in is AMQP. It is an acronym for Advanced Message Queuing Protocol.</p>
<p>So without any further ado let’s have a closer look at the AMQP protocol model.</p>
<h1 id="heading-advanced-message-queuing-protocol">Advanced Message Queuing Protocol</h1>
<p>The conceptual model of AMQP is quite simple and straightforward. It has three entities:</p>
<ol>
<li>Queue</li>
<li>Binding</li>
<li>Exchange</li>
</ol>
<p>When a publisher pushes a message to RabbitMQ, it first arrives at an exchange. The exchange then distributes copies of these messages to variously connected queues. Finally, consumers receive these messages.</p>
<p>Consider a message as a piece of data. It is necessarily a package with a payload and some meta-data. The payload contains full data whereas meta-data are properties used by RabbitMQ.</p>
<p>Figure 2 depicts a graphical representation of the AMQP model.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*F1NaCmmz72StUZZHfRfpvw.png?q=20" alt="Image" width="48" height="25" loading="lazy">
<em>Figure 2: AMQP model</em></p>
<p>AMQP is a programmable protocol. Programmers have the liberty to use libraries to configure entities (exchange, binding, and queue) as per their own needs. A RabbitMQ admin has no role in setting up these entities.</p>
<p>There are plenty of libraries available to work with RabbitMQ. You can choose from <a target="_blank" href="http://www.squaremobius.net/amqp.node/">Nodejs</a>, <a target="_blank" href="https://pypi.org/project/pika/">Python</a>, .<a target="_blank" href="https://github.com/rabbitmq/rabbitmq-dotnet-client">Net</a>, <a target="_blank" href="https://github.com/rabbitmq/rabbitmq-java-client/">Java</a>, and many more.</p>
<h1 id="heading-queues">Queues</h1>
<p>These queues are somehow similar to the queues from our data structure classes. RabbitMQ queues also follow FIFO — First-In-First-Out methodology. A queue is a place where RabbitMQ stores messages/data.</p>
<p>Programmers can configure queues through available programming libraries. You can make a queue durable ( with the <code>Durability</code> property) to safeguard your data in case the broker crashes. You can also provide a name(with the <code>Name</code> property) to a queue. Other than <code>Name</code> and <code>Durability</code>, a queue has a few other properties like auto-delete, exclusive, and arguments.</p>
<p>Before moving any further, it’s important to understand who is a direct consumer of these queues. Moreover, how many ways can a user consume messages from a queue?</p>
<h1 id="heading-consumers">Consumers</h1>
<p>Consumers are the ones who are going to use messages stored in a queue. It is possible to connect more than one consumer to a queue at a time. Consumers can either pull the message from the queue by pooling it or queues can even push the message to various connect consumers.</p>
<h1 id="heading-bindings">Bindings</h1>
<p>Bindings are the rules that a queue defines while establishing a connection with an exchange. You can have a queue connected to multiple exchanges. Every queue is also connected to a default exchange. An exchange will use these bindings to route messages to queues.</p>
<h1 id="heading-exchanges-and-their-types">Exchanges and their types</h1>
<p>An Exchange is a gateway to RabbitMQ for your messages. The distance the message has to travel inside RabbitMQ depends on the type of exchange. Primarily there are four types.</p>
<ul>
<li>Direct</li>
<li>Fanout</li>
<li>Topic</li>
<li>Header</li>
</ul>
<h2 id="heading-direct">Direct</h2>
<p>The name explains it all! — A direct exchange delivers a message directly to the queues that satisfy the below condition:</p>
<pre><code>Routing key == Binding key
</code></pre><p>A routing key is an attribute of the message. On the other hand, a binding key is something you specify while creating a binding between a queue and an exchange.</p>
<p>Figure 3 is a visual explanation of how messages flow while using a direct exchange.</p>
<p>A message originates from a producer (green circle) with a routing key — <code>img.resize</code>. Once it reaches the exchange (Orange circle), the exchange will try to find all queues with binding key — <code>img.resize</code>. In case of a match, the message is pushed to all matched queues (resize in our case). If there is no match found, the message can be sent back to the producer or can even be discarded. We are lucky that we found a match in our example ?</p>
<p>[gif image]</p>
<p>Once the message reaches the desired queue (resize in our case), they are distributed in round-robin fashion to all the connected consumers (resizer.1/resizer.2 in our case).</p>
<p>By distributing messages in a round-robin fashion, RabbitMQ makes sure that the messages are load balanced.</p>
<p>You must have noticed that the queue named <strong>crop</strong> is not receiving any messages. Because the routing key in this example is <code>img.resize</code>. To send messages to this queue, we need to send messages with a routing key that would match the binding key (say <code>img.crop</code> for instance).</p>
<h2 id="heading-fanout">Fanout</h2>
<p>A Fanout exchange ignores routing keys and distributes a message to all the connected queues. No wonder it is called Fanout (blowing messages to all connected queues! ?).</p>
<p>One of the use cases for this type of exchange is message broadcast.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2019/07/1_f4bddksBjxqZjYq3VDa3wg.gif" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Please note that RabbitMQ will still do round robin if there is more than one consumer of the queue.</p>
<h2 id="heading-topic">Topic</h2>
<p>A topic exchange routes a message by matching routing key with a pattern in the binding key.</p>
<pre><code>Routing key == Pattern <span class="hljs-keyword">in</span> binding key.
</code></pre><p>RabbitMQ uses two wild card characters for pattern matching <code>*</code> and <code>#</code>. Use a <code>*</code> to match 1 word and a <code>#</code> to match 0 or more words.</p>
<p>Figure 5 is a visual depiction of a topic exchange. Messages with routing key — <code>logs.error</code> will match patterns — <code>logs.error</code> and <code>logs.*</code>. Hence these messages will end up in the queues — <code>only error</code> and <code>all logs</code>.</p>
<p>Whereas for the producer at the bottom-left, messages with routing key— <code>logs.success</code> will match patterns of binding key <code>#success</code> and <code>logs.*</code> . Hence these messages will end up in the queues — <code>all logs</code>and <code>only success</code> .</p>
<p>[gif]</p>
<p>This type of exchange has a vast range of use cases. It can be used in the publish-subscribe pattern, distributing relevant data to desiring workers processes and many more.</p>
<h1 id="heading-header">Header</h1>
<p>A header is a particular type of exchange that routes messages based on keys present in the message header. It overlooks routing key attribute of the message.</p>
<p>When creating bindings for a header exchange, it is possible to bind a queue to match more than one header. In such a case, RabbitMQ should know from the producer if it should match all or any of these keys.</p>
<p>A producer/application can do this by providing an extra flag called ‘x-match’. ‘x-match’ can have <code>any</code> or <code>all</code> values. The first one mandates that only one value should match while the latter mandates that all must match.</p>
<h1 id="heading-message-acknowledgement">Message Acknowledgement</h1>
<p>Once a message reaches its destination, the broker should delete the message from the queue. It is necessary because a queue overflow can occur if it keeps accumulating messages.</p>
<p>Before deleting any message, the broker must have a delivery acknowledgment. There are two possible ways to acknowledge message delivery.</p>
<ol>
<li>Automatic acknowledgment: Once a consumer receives the message</li>
<li>Explicit acknowledgment: When a consumer sends back an acknowledgment</li>
</ol>
<p>In most cases, explicit acknowledgment is used as it makes sure that the consumer has consumed the message without any failover.</p>
<h1 id="heading-whats-next">What’s next</h1>
<p>RabbitMQ is a very mature and useful product. This article is only a high-level introduction to RabbitMQ. I simplified the concepts to provide a reference point for you to move further. Visit the <a target="_blank" href="https://www.rabbitmq.com/">RabbitMQ</a> website for more complex topics.</p>
<p>Hope you like the article. Don’t forget to clap(or applaud ?). Follow to read my upcoming stories. Until next time, keep Queuing.</p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
