# RabbitMQ use case 2 - WhatsApp Notification

## In this learning path

- [Introduction](https://learn.arm.com/learning-paths/servers-and-cloud-computing/rabbitmq-gcp/)
- [Learn about Arm-based cloud platforms for RabbitMQ](https://learn.arm.com/learning-paths/servers-and-cloud-computing/rabbitmq-gcp/background/)
- [Create an Azure Cobalt 100 virtual machine](https://learn.arm.com/learning-paths/servers-and-cloud-computing/rabbitmq-gcp/azure_instance/)
- [Install RabbitMQ on Azure Cobalt 100](https://learn.arm.com/learning-paths/servers-and-cloud-computing/rabbitmq-gcp/azure_installation/)
- [Validate RabbitMQ on Azure](https://learn.arm.com/learning-paths/servers-and-cloud-computing/rabbitmq-gcp/azure_baseline/)
- [Create a firewall rule for RabbitMQ](https://learn.arm.com/learning-paths/servers-and-cloud-computing/rabbitmq-gcp/gcp_firewall_setup/)
- [Create a Google Axion C4A virtual machine](https://learn.arm.com/learning-paths/servers-and-cloud-computing/rabbitmq-gcp/gcp_instance/)
- [Install RabbitMQ on Google Cloud SUSE VM](https://learn.arm.com/learning-paths/servers-and-cloud-computing/rabbitmq-gcp/gcp_installation/)
- [Validate RabbitMQ on Google Cloud](https://learn.arm.com/learning-paths/servers-and-cloud-computing/rabbitmq-gcp/gcp_baseline/)
- [RabbitMQ use Case 1 - event processing with Python Workers](https://learn.arm.com/learning-paths/servers-and-cloud-computing/rabbitmq-gcp/gcp_use_case1/)
- [RabbitMQ use case 2 - WhatsApp Notification](https://learn.arm.com/learning-paths/servers-and-cloud-computing/rabbitmq-gcp/gcp_use_case2/)
- [Next Steps](https://learn.arm.com/learning-paths/servers-and-cloud-computing/rabbitmq-gcp/_next-steps/)

## Overview
In this section you’ll implement a real-world asynchronous messaging pattern where RabbitMQ processes WhatsApp notifications reliably using a worker-based architecture.

## Why use RabbitMQ for WhatsApp notification
In production systems, sending WhatsApp notifications must be:
- Reliable
- Asynchronous
- Independent of the main application flow

RabbitMQ acts as a message broker to decouple message production from message consumption.

The architecture follows this flow:
- Application publishes a message to RabbitMQ
- RabbitMQ routes the message to a queue
- A Python worker consumes the message
- The worker simulates sending a WhatsApp notification

## Prerequisites
- GCP SUSE Arm64 virtual machine
- RabbitMQ installed and running
- RabbitMQ Management Plugin enabled
- Python 3.8 or later
- `pika` Python client library installed

## Install Python dependencies
Install Python and the RabbitMQ Python client needed to build a consumer.

```
sudo zypper install -y python3 python3-pip
pip3 install pika
```

## Understand the RabbitMQ topology
This use case uses a direct exchange topology for exact-match routing.

**Exchanges:**
- `notifications` (direct): Routes WhatsApp notification messages based on an exact routing key match.

**Queue:**
- `whatsapp.notifications` (durable): Stores WhatsApp messages persistently until they are consumed by a worker.

**Binding:**
- Exchange: `notifications`
- Routing key: `whatsapp`
- Queue: `whatsapp.notifications`

This ensures only WhatsApp-related messages are routed to the final destination for processing.

## Declare RabbitMQ resources
Create the required exchange, queue, and binding for WhatsApp notifications.

```
./rabbitmqadmin declare exchange \
  name=notifications \
  type=direct \
  durable=true

./rabbitmqadmin declare queue \
  name=whatsapp.notifications \
  durable=true

./rabbitmqadmin declare binding \
  source=notifications \
  destination=whatsapp.notifications \
  routing_key=whatsapp
```
Each command confirms successful creation.

## Validate the setup
Verify that RabbitMQ resources exist and are correctly connected.

```
./rabbitmqadmin list queues name messages
./rabbitmqadmin list exchanges name type
./rabbitmqadmin list bindings
```

- `list queues` displays all queues along with the number of messages currently stored in each queue.
- `list exchanges` lists all exchanges and their types, allowing verification of correct exchange configuration.
- `list bindings` shows how exchanges, queues, and routing keys are connected.

The output shows you the following:
- `notifications` exchange of type direct
- `whatsapp.notifications` durable queue
- Correct routing key binding (`whatsapp`)
- Zero or more queued messages

This confirms topology correctness before consuming messages.

```
__output__
> ./rabbitmqadmin list queues name messages
+------------------------+----------+
|          name          | messages |
+------------------------+----------+
| jobs                   | 0        |
| order.events           | 1        |
| testqueue              | 1        |
| whatsapp.notifications | 0        |
+------------------------+----------+

__output__
> ./rabbitmqadmin list exchanges name type
+--------------------+---------+
|        name        |  type   |
+--------------------+---------+
|                    | direct  |
| amq.direct         | direct  |
| amq.fanout         | fanout  |
| amq.headers        | headers |
| amq.match          | headers |
| amq.rabbitmq.trace | topic   |
| amq.topic          | topic   |
| events             | topic   |
| notifications      | direct  |
+--------------------+---------+

__output__
> ./rabbitmqadmin list bindings
+---------------+------------------------+------------------------+
|    source     |      destination       |      routing_key       |
+---------------+------------------------+------------------------+
|               | jobs                   | jobs                   |
|               | order.events           | order.events           |
|               | testqueue              | testqueue              |
|               | whatsapp.notifications | whatsapp.notifications |
| events        | order.events           | order.*                |
| notifications | whatsapp.notifications | whatsapp               |
+---------------+------------------------+------------------------+
```

## Implement the WhatsApp worker
Create a Python consumer (worker) that processes WhatsApp notification messages from the queue.

Create a file named `whatsapp_worker.py` with the following code:

```python
import pika
import json
import time

RABBITMQ_HOST = "localhost"
RABBITMQ_VHOST = "/"
RABBITMQ_USER = "guest"
RABBITMQ_PASS = "guest"
QUEUE_NAME = "whatsapp.notifications"

credentials = pika.PlainCredentials(RABBITMQ_USER, RABBITMQ_PASS)

parameters = pika.ConnectionParameters(
    host=RABBITMQ_HOST,
    virtual_host=RABBITMQ_VHOST,
    credentials=credentials,
    heartbeat=60
)

print("[DEBUG] Connecting to RabbitMQ...")
connection = pika.BlockingConnection(parameters)
channel = connection.channel()

print("[DEBUG] Declaring queue...")
channel.queue_declare(queue=QUEUE_NAME, durable=True)

print("[DEBUG] Setting QoS...")
channel.basic_qos(prefetch_count=1)

print("WhatsApp Worker started. Waiting for messages...")

def send_whatsapp(ch, method, properties, body):
    data = json.loads(body.decode())
    print(f"[Worker] Sending WhatsApp message to {data['phone']}")
    print(f"[Worker] Message content: {data['message']}")

    # Simulate external WhatsApp API call
    time.sleep(1)

    print("[Worker] Message sent successfully")
    ch.basic_ack(delivery_tag=method.delivery_tag)

channel.basic_consume(
    queue=QUEUE_NAME,
    on_message_callback=send_whatsapp,
    auto_ack=False
)

print("[DEBUG] Starting consumer loop (this should block)...")
channel.start_consuming()
```

## Start the worker
Run the worker in a dedicated terminal session:

```
python3 whatsapp_worker.py
```

The worker runs correctly and waits for messages without exiting.

The output is similar to:

```
__output__
[DEBUG] Connecting to RabbitMQ...
[DEBUG] Declaring queue...
[DEBUG] Setting QoS...
WhatsApp Worker started. Waiting for messages...
[DEBUG] Starting consumer loop (this should block)...
```

The process blocks without returning to the shell prompt.

## Publish a test message
Open another SSH terminal and publish a WhatsApp notification message to RabbitMQ.

```
./rabbitmqadmin publish \
  exchange=notifications \
  routing_key=whatsapp \
  payload='{"phone":"+911234567890","message":"Hello from RabbitMQ"}'
```

The output appears in the first terminal running `whatsapp_worker.py`:

```
__output__
[Worker] Sending WhatsApp message to +911234567890
[Worker] Message content: Hello from RabbitMQ
[Worker] Message sent successfully
```

## Validate message consumption
The worker terminal displays the complete log:

```
__output__
[DEBUG] Connecting to RabbitMQ...
[DEBUG] Declaring queue...
[DEBUG] Setting QoS...
WhatsApp Worker started. Waiting for messages...
[DEBUG] Starting consumer loop (this should block)...
[Worker] Sending WhatsApp message to +911234567890
[Worker] Message content: Hello from RabbitMQ
[Worker] Message sent successfully
```

This confirms:
- Message routing works correctly
- Queue consumption is successful
- Manual acknowledgments are applied

This validates the end-to-end message flow.

## Verify queue state
```
./rabbitmqadmin list queues name messages consumers
```

The output is similar to:

```
__output__
+------------------------+----------+-----------+
|          name          | messages | consumers |
+------------------------+----------+-----------+
| jobs                   | 0        | 0         |
| order.events           | 2        | 0         |
| testqueue              | 1        | 0         |
| whatsapp.notifications | 0        | 1         |
+------------------------+----------+-----------+
```

This confirms:
- Messages were consumed successfully
- One active consumer is connected
- No backlog remains in the queue

## What you’ve accomplished
In this use case, you:
- Configured a direct exchange topology for exact-match routing
- Created durable queues and bindings for WhatsApp notifications
- Implemented a Python worker using the `pika` library
- Published test messages and validated end-to-end message flow
- Confirmed reliable message consumption with manual acknowledgments

This pattern demonstrates how RabbitMQ enables asynchronous, decoupled communication for notification systems on Arm-based cloud platforms.
