EventGrid のフィルタを試してみる

[EventGrid](https://docs.microsoft.com/ja-jp/azure/event-grid/) は publish/subscribe 型のイベントの仕様を可能にするイベントルーティングサービスです。

<img width="641" alt="event-grid-functional-model.png" src="https://qiita-image-store.s3.amazonaws.com/0/3470/f30f794c-bef6-0d9e-5d77-b39ea413b517.png">

上記のEvent Publishers で書かれている様々なイベントを拾うことができ、それを、EventSubscrber に通知します。ほぼリアルタイムで実施でき、イベント配信も、Exponential Backoff のアルゴリズムで確実にイベントを配信するようになっています。

じゃあ、Service Bus との違いは何よ？となるとおもうのですが、それはこのドキュメントにまとまっていました。

# Messaging サービスの選択

* [メッセージを配信する Azure サービスの選択](https://docs.microsoft.com/ja-jp/azure/event-grid/compare-messaging-services)

抜粋すると

| サービス | 目的 | 型 | 使用時の注意 |
|:---------|:-----------------|:-------|:---------|
| Event Grid | リアクティブプログラミング | イベント配信 | 状態の変更に反応する |
| Event Hub | ビッグデータのパイプライン | イベントのストリーミング | テレメトリと分散データストリーミング |
| Service Bus | 高価値のエンタープライズメッセージング | メッセージ | 注文処理や金融取引 |

この表は分かりやすいですね。　EventGrid は特に

 * 動的にスケーラブル
 * 低コスト　（定期的なポーリングが不要なので）
 * サーバーレス

という特徴を持っているようです。Service Bus は、Publish/Subscribe 以外にも、Queue / Relay なども持っていますが。また、重複検出や、FIFO などの特徴を持っています

* ポーリングが必要な信頼性の高い非同期メッセージ配信 (サービスとしてのエンタープライズ メッセージング)
* 高度なメッセージング機能 (FIFO、バッチ処理/セッション、トランザクション、配信不能処理、一時的制御、ルーティングとフィルタリング、重複検出など)


となると、Service Bus と、Storage Queue との違いは、、、となるのですが、下記のドキュメントがあります。

 * [Storage queues and Service Bus queues - compared and contrasted](https://docs.microsoft.com/en-us/azure/service-bus-messaging/service-bus-azure-and-service-bus-queues-compared-contrasted)

かなり詳細な比較になっていますが、ざっくりいうと、より信頼性の高いものが必要な時に、Service Bus, FIFO不要、重複検出不要で 多少ロストしても、再トライすればいいやんというレベルのはStorage Queue でいいのだと思います。（あとは細かい違いは上記ドキュメント参照）

# カスタムトピックとAzure Functions を使って概念を理解する

実際にカスタムトピックを作って、そこにメッセージを投げて、それがちゃんとAzure Functions にルーティングされるか確かてめてみましょう。

## カスタムトピックの作成

Azure CLI 2.0 (Azure Portal のコンソールからも使えます）を使って、Event Grid のトピックを作ります。

```
$ az group create --name gridResourceGroup2 --location westus2    // Resource Group の作成
$ az eventgrid topic create --name sometopic -l westus2 gridResourceGroup2 // EventGrid Topic の作成
```

これで、イベントを受け付ける EventGrid のTopic が出来上がりました。しっかりエンドポイントもできているようです。

```
$ az eventgrid topic list
          :
    "endpoint": "https://sometopic.westus2-1.eventgrid.azure.net/api/events",
    "id": "/subscriptions/YOURSUBSCRIPTION/resourceGroups/gridResourceGroup2/providers/Microsoft.EventGrid/topics/sometopic",
    "location": "westus2",
    "name": "sometopic",
    "provisioningState": "Succeeded",
    "resourceGroup": "gridResourceGroup2",
    "tags": null,
    "type": "Microsoft.EventGrid/topics"
  },
            :
```

ちなみに、Blob ストレージのトリガなどの場合は、既に、トピックが作成されているので、自分で作る必要はありません。カスタムの場合は、自分でこのエンドポイントにメッセージを投げてルーティングしてもらいます。

## イベントへのサブスクライブ

じゃあ、そのイベントにサブスクライブしてみましょう。Azure Functions で、EventGrid トリガーを GUI で設定することができます。

<img width="455" alt="2017-12-20_13h33_59.png" src="https://qiita-image-store.s3.amazonaws.com/0/3470/1de2c3ff-6cc4-0177-0f21-d265bbbb1d63.png">


しかし、やっていることは、単純に、先ほど作成した、Topic にサブスクライブするイベントサブスクリプションを作成しただけなので、本当はコマンドラインでも実施可能です。（後は、function.jsonにイベントサブスクリプションを追加したら同じ）

```
$ az eventgrid topic event-subscription list --topic-name sometopic -g gridResourceGroup2
   :
    "id": "/subscriptions/YOUR_SUBSCRIPTION/resourceGroups/gridResourceGroup2/providers/Microsoft.EventGr
id/topics/sometopic/providers/Microsoft.EventGrid/eventSubscriptions/sometopic",
    "labels": [
      ""
    ],
    "name": "sometopic",
    "provisioningState": "Succeeded",
    "resourceGroup": "gridResourceGroup2",
    "topic": "/subscriptions/YOUR_SUBSCRIPTION/resourceGroups/gridresourcegroup2/providers/microsoft.even
tgrid/topics/sometopic",
    "type": "Microsoft.EventGrid/eventSubscriptions"
  },
  {
    "destination": {
      "endpointBaseUrl": "https://eventexample.azurewebsites.net/admin/extensions/EventGridExtensionConfig",
      "endpointType": "WebHook",
      "endpointUrl": null
    },
    "filter": {
      "includedEventTypes": [
        "All"
      ],
      "isSubjectCaseSensitive": null,
      "subjectBeginsWith": "",
      "subjectEndsWith": ""
    },
   :
```

先ほどの画面と入力項目がさほど違わないのがわかるのと思います。このような手順で、１つのトピックに対して、２つのEventGrid トリガーの Azure Functions を作成してみます。

# メッセージの送信

メッセージを送信してみます。

```
$ endpoint=$(az eventgrid topic show --name sometopic -g gridResourceGroup2 --query "endpoint" --output tsv)
$ key=$(az eventgrid topic key list --name sometopic -g gridResourceGroup2 --query "key1" --output tsv)
$ body=$(eval echo "'$(curl https://raw.githubusercontent.com/Azure/azure-docs-json-samples/master/event-grid/customevent.json)'")
$ curl -X POST -H "aeg-sas-key: $key" -d "$body" $endpoint
```

ちなみに、ここで、送信されている Body の中身は

```json
[
    {
        "id": "'"$RANDOM"'",
        "eventType": "recordInserted",
        "subject": "myapp/vehicles/motorcycles",
        "eventTime": "'`date +%Y-%m-%dT%H:%M:%S%z`'",
        "data":{
            "make": "Ducati",
            "model": "Monster"
        }
    }
]
```

`eval` メソッドでこれが[評価される](https://orebibou.com/2015/01/%E3%82%B7%E3%82%A7%E3%83%AB%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%97%E3%83%88%E3%81%A7eval%E3%82%B3%E3%83%9E%E3%83%B3%E3%83%89%E3%82%92%E7%94%A8%E3%81%84%E3%81%9F%E5%A4%89%E6%95%B0%E3%81%AE2%E9%87%8D/)ので、実際の Body は

```json
$ echo $body
[
   {
      "id":"2145",
      "eventType":"recordInserted",
      "subject":"myapp/vehicles/motorcycles",
      "eventTime":"2017-12-20T04:45:45+0000",
      "data":{
         "make":"Ducati",
         "model":"Monster"
      }
   }
]
```

次のように展開される。これをTopic のエンドポイントにポストするだけ。

<img width="756" alt="fire01.png" src="https://qiita-image-store.s3.amazonaws.com/0/3470/80c8145e-e657-1ec2-637c-68ba3c99fda3.png">

両方同時に動きました！狙い通り。

<img width="1368" alt="fire02.png" src="https://qiita-image-store.s3.amazonaws.com/0/3470/b55f4c85-c0b8-ef3e-2a7f-a350b6887709.png">

# フィルタリングの実施

EventGrid の利点の一つにフィルタリングが出来ることがある。あのメッセージのうち何がフィルタリングできるんだろう？

* [Event Grid サブスクリプション スキーマ](https://docs.microsoft.com/ja-jp/azure/event-grid/subscription-creation-schema)

`subject` と `eventType` をフィルタリングできる様子。上記のカスタムトピックでは、`eventType` は自由に決められるし、`subject` も自分で決められる。このルールを考えると、publish/subscribe型で自由にルーティング・フィルタが出来そう。
`az` コマンドでもいいけど、せっかくなのでもう一つ Azure Functions を作ってみる。そして、EventSubscriptionを作ってみる。

<img width="434" alt="filter.png" src="https://qiita-image-store.s3.amazonaws.com/0/3470/0c684381-352e-831f-6cfb-63dd05585ecf.png">

Prefix Filterというのがある。これは。`subject` のフィルターのこと。これは、仕様を見ればよくわかる。

* [az eventgrid topic event-subscription](https://docs.microsoft.com/ja-jp/cli/azure/eventgrid/topic/event-subscription?view=azure-cli-latest#az_eventgrid_topic_event_subscription_create)

```
az eventgrid topic event-subscription create --endpoint
                                             --name
                                             --resource-group
                                             --topic-name
                                             [--endpoint-type {eventhub, webhook}]
                                             [--included-event-types]
                                             [--labels]
                                             [--subject-begins-with]
                                             [--subject-case-sensitive {false, true}]
                                             [--subject-ends-with]
```

他にも指定できる項目もあるが、その場合は、`az` コマンドで指定する必要があるっぽい。

# フィルタされるイベントの送信

さっきのメッセージを送信しても、新しく作ったフィルタ付きのFunctionは反応しない。`premium/event` で始まる `subject`を持つものしか反応しないはずなので正解。

<img width="940" alt="doesntfire.png" src="https://qiita-image-store.s3.amazonaws.com/0/3470/1a805d24-1760-fe32-9829-7845c2fe36ff.png">

じゃあ、反応するメッセージも試してみる。
こんなファイルを作ってみよう。

_data.txt_

```
[
  {
    "id": "'"$RANDOM"'",
    "eventType": "premiumInsert",
    "subject": "premium/event/01",
    "eventTime": "'`date +%Y-%m-%dT%H:%M:%S%z`'",
    "data": {
        "make": "Microsoft",
        "model": "Durable"
    }
  }
]
```

次のコマンドでポストする。Topic は何もかわらず、EventSubscription のフィルタ付きが一つ増えただけなので、エンドポイントなどは同じ。

```
$ body2=$(eval echo "'$(cat data.txt)'")
$ curl -X POST -H "aeg-sas-key: $key" -d "$body" $endpoint
```

<img width="707" alt="filterok.png" src="https://qiita-image-store.s3.amazonaws.com/0/3470/eef0725a-8ea4-99a3-776e-79d1d2d13131.png">

完璧。どちらも反応してくれました。このフィルタは便利ですね。Storage Triggerもポーリングベースで、Service Busもオペレーションごとにコストがかかります。Event Grid は、信頼性も高く、スケールし、低コスト（どれぐらい安くなるかしらんけど）の基盤で、今後サポートされるリソースも増えると思うのでメッセージングの基盤として、相当楽しみですね。がっつり使っていこう。

次は、Service Bus とかのサービスを使って違いを把握して、性能評価なども実施していきたいと思っています。

# Resource 

* [EventGrid](https://docs.microsoft.com/ja-jp/azure/event-grid/)
* [メッセージを配信する Azure サービスの選択](https://docs.microsoft.com/ja-jp/azure/event-grid/compare-messaging-services)
* [Storage queues and Service Bus queues - compared and contrasted](https://docs.microsoft.com/en-us/azure/service-bus-messaging/service-bus-azure-and-service-bus-queues-compared-contrasted)
* [az eventgrid topic event-subscription](https://docs.microsoft.com/ja-jp/cli/azure/eventgrid/topic/event-subscription?view=azure-cli-latest#az_eventgrid_topic_event_subscription_create)
* [Event Grid サブスクリプション スキーマ](https://docs.microsoft.com/ja-jp/azure/event-grid/subscription-creation-schema)
* [Azure CLI と Event Grid を使用したカスタム イベントの作成とルーティング](https://docs.microsoft.com/ja-jp/azure/event-grid/custom-event-quickstart)