【ローカル環境編】Azure Functions RabbitMQ Extension を使用してみる

## はじめに

2020 年 12 月 22 日に、Azure Functions の新たなトリガーである RabbitMQ の Extension が GA (Generally Available: 一般公開) されました。この拡張機能を使用することにより、Azure Functions は、RabbitMQ の Queue へ入っているキューを取り出しての処理や、メッセージを作成して、別の Queue へ格納することができます。

[RabbitMQ Extension for Windows and Linux is now generally available](https://azure.microsoft.com/ja-jp/updates/rabbitmq-extension-for-windows-and-linux-is-now-generally-available/)

現時点で使用できる App Service Plan は、Premium, Dedicated (App Service) Plan となっており、Consumption Plan は対応しておりませんので注意が必要です。 詳しい内容は、GitHub の Rabbit MQ Extensions リポジトリがございますのでこちらにて最新情報を確認することができます。

[Azure/azure-functions-rabbitmq-extension](https://github.com/Azure/azure-functions-rabbitmq-extension)


## 準備

RabbitMQ と Azure Functions の事前準備として以下のソフトウェアをインストールしておきます。

- Docker
- Visual Studio

### RabbitMQ の環境構築
今回ローカル環境で開発するために、RabbitMQ のソフトウェアを直接ダウンロードする方法がありますが、Docker コンテナとして実行しそのコンテナを Azure プラットフォーム上へデプロイすることを想定しておりますため、Docker 上で構築を行います。

1) Docker Hub から、対象の RabbitMQ の Docker image を pull します。UI 画面にて操作を行いたいため、管理画面が付いております `3-management` を選択しました。
https://hub.docker.com/_/rabbitmq

```
$ docker pull rabbitmq:3-management
```

2) RabbitMQ のコンテナを立ち上げます。UI 画面を使用するために、15672 ポートと メッセージのやり取りにて AMQP を使用するために、5672 ポートをフォワードするようにします。

```
$ docker run -d --hostname my-rabbit --name some-rabbit -p 8080:15672 -p 5672:5672　rabbitmq:3-management
```

3) http://localhost:8080/ へアクセスを行い、RabbitMQ の UI 画面にてログインを行います。デフォルトの設定では、以下のようになっております。

- ユーザ名：guest
- パスワード：guest

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149402/83b7b874-70ef-c202-3212-52a2e0bac707.png)

4) メッセージの Queue を転送するための Exchange を作成します。上部メニューの Exchange から、`Add a new exchange` から行います。Name に `test` と追加し、`Add exchange` ボタンを押します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149402/882101b0-d937-ae09-ea6a-78c5e5805c6f.png)

5) Queue の作成を行います。上部メニューの Queues から、Azure Functions からメッセージを取得する Queue である `test` を作成し、取得したメッセージを別の Queue へ転送する `test2` を作成します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149402/e391c188-34ab-119f-2354-732810341694.png)

5) 作成した `test` queue に 4) で作成した Exchange と紐づけるため、`test` のExchange を Bind します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149402/7cad6105-fb0e-6093-d532-bb505b9ce748.png)



### Azure Functions プロジェクトの作成

1) Azure Functions のプロジェクトを作成し、最初はトリガー設定は空とします。

2) RabbitMQ の Extension をインストールするために、作成したプロジェクトから右クリックをし、`NuGetパッケージの管理` を選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149402/5b0e4979-cc3d-299c-5713-41a3778e15ac.png)

3) 検索画面から、プレリリースのチェックボックスを選択し、`Microsoft.Azure.WebJobs.Extensions.RabbitMQ`を検索後にインストールを行います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149402/432d5fd3-9adb-3606-fd60-965832d6da5b.png)

4) local.settings.json にて、Azure Functions が RabbitMQ へ接続するための設定を記載します。今回はローカル環境での設定となっておりますが、Azure プラットフォームや他の環境へ RabbitMQ がデプロイされている場合には、適宜設定値を変更してください。

```
{
    "IsEncrypted": false,
  "Values": {
    "AzureWebJobsStorage": "UseDevelopmentStorage=true",
    "FUNCTIONS_WORKER_RUNTIME": "dotnet",
    "RabbitMQConnectionName": "amqp://guest:guest@localhost:5672",
    "HostNameAppSetting": "localhost",
    "UserNameAppSetting": "guest",
    "PasswordAppSetting": "guest"
  }
}
```

5) あらかじめ作成した関数コード（Function1.cs）に以下の処理を行うコードを記述します。

#### Timer Trigger を使用して 1 分毎に Queue へメッセージを送信する関数

QueueName = "test" となっており、test Queue へ現在時刻のメッセージを送信します。

```
        [FunctionName("OutputFunction")]
        public static void Run2([TimerTrigger("0 */1 * * * *")] TimerInfo myTimer,
        [RabbitMQ(
                ConnectionStringSetting = "RabbitMQConnectionName",
                QueueName = "test")] out string outputMessage,
        ILogger log)
        {
            String now_datetime = DateTime.Now.ToString();
            log.LogInformation($"C# Timer trigger function executed at: {now_datetime}");
            outputMessage = now_datetime;
        }
```

#### Queue から取得したメッセージを別の Queue へ転送する関数

Azure Functions が `test` Queue へ入ったことを検知して、メッセージを取り出して、`test2` Queue へ受け流しをします。

```
        [FunctionName("InputFunction")]
        public static void Run(
            [RabbitMQTrigger("test", ConnectionStringSetting = "RabbitMQConnectionName")] string inputMessage,
            [RabbitMQ(
                ConnectionStringSetting = "RabbitMQConnectionName",
                QueueName = "test2")] out string outputMessage,
            ILogger logger)
            {
                outputMessage = inputMessage;
                logger.LogInformation($"RabittMQ output binding function sent message: {outputMessage}");
            }
```

## 検証結果

### Azure Functions からの実行画面

赤枠で囲まれている部分は、Timer Trigger によって発行された DateTime のメッセージを `test` Queue へ転送しています。

緑枠で囲まれている部分は、RabbitMQ Trigger にて `test` Queue へメッセージが格納されたので、取得を行い `test2` Queue へ転送されました。

![スクリーンショット 2020-12-29 165818.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149402/8afa12c5-e140-3ce9-7479-1aeebc61b7c7.png)


### RabbitMQ からの実行画面

#### test Queue

Azure Functions の実行を一時止めたのですが、test Queue の画面を見るとメッセージは全てはけていることが分かります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149402/3cadc61a-145d-bc72-8e0a-2a09447036ad.png)

#### test2 Queue

test2 の画面では、Ready が 2 になっており、メッセージが 2 件格納されていることが分かります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149402/3eec7220-f78d-af55-7d5c-cbf740d661b9.png)

下画面にあります メッセージを取得する機能を利用すると、Payload に Datetime の内容が格納されています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149402/696b545c-175b-8f0f-08c8-df75ca575f65.png)


## まとめ
いかがでしたでしょうか。GA されたばかりの Azure Functions RabbitMQ Extension をローカル環境にて実行する内容になりましたが、Azure Functions 側では、すでにあるキューイングサービスの Kafka Extension と同様にパッケージをインストールしコードを書くことですぐに構築することができました。


## 参考文献
- [Azure/azure-functions-rabbitmq-extension](https://github.com/Azure/azure-functions-rabbitmq-extension)
- [Announcing the RabbitMQ extension for Azure Functions](https://dev.to/azure/announcing-the-rabbitmq-extension-for-azure-functions-2mbo)