# Azure Service Bus

Azure Service Bus queues - credentials, channels and outgoing connections, with acknowledging and rejecting messages.

Zato integrates with Microsoft Azure Service Bus, letting you receive and send messages from Azure queues in your Python services.

After adding a connection, such as the one below, your services will be able to receive and send messages without any additional configuration or programming.

## Getting credentials from Azure {#getting-credentials-from-azure}

Assuming you have an Azure Service Bus namespace and a queue created, you need to create a Shared Access Policy to authenticate Zato with Azure Service Bus. You can create one at the namespace level (applies to all queues) or at the queue level (applies only to that queue).

For namespace-level policy:

1. Open your Service Bus namespace
2. In the left menu, click **Shared access policies**
3. Click **\+ Add**
4. Enter a policy name, e.g. `MyPolicyName`, and note that it will later become your username in the connection string
5. Select the permissions:
6. **Listen** - to receive messages
7. **Send** - to send messages
8. Click **Create**

## Getting the connection details {#getting-the-connection-details}

1. Click on your newly created policy and select **Show AMQP connection string**
2. Copy the primary connection string, the secondary one is not used

## Extracting information from the AMQP connection string {#extracting-information-from-the-amqp-connection-string}

The string will look like this in the screenshot below, and you'll need to extract a couple of things from it:

1. Protocol - must be `amqps`
2. Username - your policy name
3. Password - password for that policy
4. Address - your namespace hostname (e.g. `mycompany-dev.servicebus.windows.net`) and port 5671
5. "?verify=verify\_none" - ignore this, it's not used by Zato

## Configuring Zato {#configuring-zato}

In Zato, you create channels that will listen for messages from the bus. To send messages to queues, you create an outgoing connection. Both will rely on the connection details extracted in the previous step.

A single channel listens for messages from a single queue. An outgoing connection, on the other hand, can be used to send messages to any queue by its name.

### Channels to receive messages {#channels-to-receive-messages}

1. Go to **Connections** → **Message queues** → **Azure Service Bus** → **Channels**
2. Click **Create a new Azure Service Bus channel**
3. Fill in the details as in the screenshot below, set the data format to JSON, and click OK

With the JSON data format, the body of each message is parsed before the service runs, and the service reads the fields of the message directly.

Service `demo.input-logger` is a useful one because it logs all the messages it receives, so you can send some test messages to your queue, and it will log everything as soon as it receives them.

### Outgoing connections to send messages {#outgoing-connections-to-send-messages}

1. Go to **Connections** → **Message queues** → **Azure Service Bus** → **Outgoing**
2. Click **Create a new outgoing Azure Service Bus connection**
3. Fill in the details as in the screenshot below, and click OK

The same pages are also available under **Cloud** → **Microsoft** → **Azure Service Bus** and **Vendors** → **Microsoft** → **Azure Service Bus**.

## Receiving messages {#receiving-messages}

Once you have configured a channel, Zato will automatically invoke your service for each message received from the Azure queue.

- The message body is available in `self.request.input`. With the JSON data format, it is the parsed message and the service reads its fields by name, e.g. `self.request.input['flight_no']`. With any other data format, it is the body as text.
- The delivery itself is available in `self.request.amqp`, and that lets you control whether you want to acknowledge or reject a given message.

### Acknowledging and rejecting messages {#acknowledging-and-rejecting-messages}

When you receive a message from Azure Service Bus, you control what happens to it:

- **self.request.amqp.ack()** - Acknowledges the message. This removes it from the queue permanently. Use this when you have successfully processed the message.

- **self.request.amqp.reject()** - Rejects the message. This releases it back to the queue so it can be delivered again. Use this when processing failed and you want to receive the message later to try again.

If the service does neither, the channel's acknowledgment mode governs what happens to the message once the service completes, and a message whose service raised an exception is released back to the queue.

### Basic example {#basic-example}

A minimal service that receives a message and acknowledges it:

```python
from zato.server.service import Service

class FlightStatusHandler(Service):

    def handle(self):

        # Log what we received
        self.logger.info('Flight status update: %s', self.request.input)

        # Acknowledge the message - removes it from the queue
        self.request.amqp.ack()
```

### Updating flight information displays {#updating-flight-information-displays}

In this example, an airport operations system receives flight status updates from Azure Service Bus and forwards them to a flight information display system (FIDS) via REST API. If the update fails, the message is rejected so it can be retried.

```python
from zato.server.service import Service

class ProcessFlightUpdate(Service):

    def handle(self):

        # The parsed message
        data = self.request.input

        try:
            # Extract flight information
            flight_no = data['flight_no']
            status = data['status']
            gate = data['gate']

            # Update the flight information display system
            conn = self.rest['FlightDisplayAPI']
            conn.post({
                'flight': flight_no,
                'status': status,
                'gate': gate
            })

            # Success - acknowledge the message
            self.request.amqp.ack()

        except Exception as e:
            self.logger.error('Failed to process flight %s: %s', data['flight_no'], e)

            # Processing failed - reject so it can be retried
            self.request.amqp.reject()
```

For more ways to receive messages in your services, read the [AMQP usage examples](https://zato.io/docs/dev/examples/amqp.html).

## Sending messages {#sending-messages}

Use the outgoing AMQP connection to send messages to Azure Service Bus queues.

The destination queue is named by the `routing_key` argument of each publication, so one outgoing connection sends messages to any queue in its namespace.

### Basic example {#basic-example_1}

A minimal service that sends a message to an Azure queue:

```python
from json import dumps

from zato.server.service import Service

class SendFlightAlert(Service):

    def handle(self):
        msg = {'flight_no': 'LH123', 'status': 'delayed', 'delay_minutes': 30}
        self.out.amqp.publish('Azure Queue Outgoing', dumps(msg), routing_key='flight-alerts')
```

### Publishing boarding notifications {#publishing-boarding-notifications}

This service publishes boarding notifications to Azure Service Bus when a flight is ready for boarding. Other systems (mobile apps, display boards, airline staff devices) subscribe to this queue.

```python
from json import dumps

from zato.server.service import Service

class PublishBoardingNotification(Service):

    def handle(self):

        data = self.request.input

        notification = {
            'flight_no': data['flight_no'],
            'gate': data['gate'],
            'boarding_time': data['boarding_time'],
            'status': 'now_boarding',
            'zones': data['zones']
        }

        self.out.amqp.publish('Azure Queue Outgoing', dumps(notification), routing_key='boarding-notifications')

        self.logger.info('Published boarding notification for %s at gate %s',
            data['flight_no'], data['gate'])
```

For more ways to send messages from your services, read the [AMQP usage examples](https://zato.io/docs/dev/examples/amqp.html).

## Learn more {#learn-more}

- [Development documentation](https://zato.io/docs/dev/) - The complete reference for writing services
- [Requests and responses](https://zato.io/docs/dev/request-response/) - What a service receives, what it returns and how both are structured
- [Integration examples](https://zato.io/docs/dev/examples/) - Ready-made code for the systems you are likely to connect to
- [IDE and debugging](https://zato.io/docs/dev/ide/) - Write services in the Dashboard or in your own editor
- [Data models](https://zato.io/docs/dev/model/) - Declare inputs and outputs and have them validated for you
- [In-depth API tutorial](https://zato.io/tutorials/main/01.html) - The full platform tutorial, from installation to production patterns
