🕌

【MS Learn】アプリケーションと Azure Queue Storage の間で通信する をやってみた

2023/12/18に公開

はじめに

やってみたシリーズです。
今回は Azure Queue Storage を使ってみます。
対象のトレーニングはこちら。
https://learn.microsoft.com/ja-jp/training/modules/communicate-between-apps-with-azure-queue-storage/

演習 - ストレージ アカウントを作成する

サンドボックス環境が用意されるので、その環境で実行していきます。

Azure CLI を使用してストレージ アカウントを作成する

生成されたコマンドを元に用意された Azure Cloud Shell で実行します。

Azure Cloud Shell
$ az storage account create -g learn-759f9aad-33f7-473a-9f8b-c3d324621976 --kind StorageV2 --sku Standard_LRS --name learn759f9aadstorage

{
  "accessTier": "Hot",
  "accountMigrationInProgress": null,
  "allowBlobPublicAccess": false,
  "allowCrossTenantReplication": false,
  "allowSharedKeyAccess": null,
  "allowedCopyScope": null,
  "azureFilesIdentityBasedAuthentication": null,
  "blobRestoreStatus": null,
  "creationTime": "2023-12-18T08:26:51.707246+00:00",
  "customDomain": null,
  "defaultToOAuthAuthentication": null,
  "dnsEndpointType": null,
  "enableHttpsTrafficOnly": true,
  "enableNfsV3": null,
  "encryption": {
    "encryptionIdentity": null,
    "keySource": "Microsoft.Storage",
    "keyVaultProperties": null,
    "requireInfrastructureEncryption": null,
    "services": {
      "blob": {
        "enabled": true,
        "keyType": "Account",
        "lastEnabledTime": "2023-12-18T08:26:51.972880+00:00"
      },
      "file": {
        "enabled": true,
        "keyType": "Account",
        "lastEnabledTime": "2023-12-18T08:26:51.972880+00:00"
      },
      "queue": null,
      "table": null
    }
  },
  "extendedLocation": null,
  "failoverInProgress": null,
  "geoReplicationStats": null,
  "id": "/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/learn-759f9aad-33f7-473a-9f8b-c3d324621976/providers/Microsoft.Storage/storageAccounts/learn759f9aadstorage",
  "identity": null,
  "immutableStorageWithVersioning": null,
  "isHnsEnabled": null,
  "isLocalUserEnabled": null,
  "isSftpEnabled": null,
  "isSkuConversionBlocked": null,
  "keyCreationTime": {
    "key1": "2023-12-18T08:26:51.800968+00:00",
    "key2": "2023-12-18T08:26:51.800968+00:00"
  },
  "keyPolicy": null,
  "kind": "StorageV2",
  "largeFileSharesState": null,
  "lastGeoFailoverTime": null,
  "location": "westus",
  "minimumTlsVersion": "TLS1_0",
  "name": "learn759f9aadstorage",
  "networkRuleSet": {
    "bypass": "AzureServices",
    "defaultAction": "Allow",
    "ipRules": [],
    "ipv6Rules": [],
    "resourceAccessRules": null,
    "virtualNetworkRules": []
  },
  "primaryEndpoints": {
    "blob": "https://learn759f9aadstorage.blob.core.windows.net/",
    "dfs": "https://learn759f9aadstorage.dfs.core.windows.net/",
    "file": "https://learn759f9aadstorage.file.core.windows.net/",
    "internetEndpoints": null,
    "microsoftEndpoints": null,
    "queue": "https://learn759f9aadstorage.queue.core.windows.net/",
    "table": "https://learn759f9aadstorage.table.core.windows.net/",
    "web": "https://learn759f9aadstorage.z22.web.core.windows.net/"
  },
  "primaryLocation": "westus",
  "privateEndpointConnections": [],
  "provisioningState": "Succeeded",
  "publicNetworkAccess": null,
  "resourceGroup": "learn-759f9aad-33f7-473a-9f8b-c3d324621976",
  "routingPreference": null,
  "sasPolicy": null,
  "secondaryEndpoints": null,
  "secondaryLocation": null,
  "sku": {
    "name": "Standard_LRS",
    "tier": "Standard"
  },
  "statusOfPrimary": "available",
  "statusOfSecondary": null,
  "storageAccountSkuConversionStatus": null,
  "tags": {},
  "type": "Microsoft.Storage/storageAccounts"
}

演習 - キューを識別する

スターター アプリケーションを複製して開く

  1. ソリューションを複製します。
Azure Cloud Shell
$ cd ~
$ git clone https://github.com/MicrosoftDocs/mslearn-communicate-with-storage-queues.git
  1. ディレクトリをスターター フォルダーに変更し、Cloud Shell エディターを開きます。
Azure Cloud Shell
$ cd mslearn-communicate-with-storage-queues/start/
$ code .

Azure.Storage.Queues NuGet パッケージ

スターター アプリケーションには、Azure.Storage.Queues パッケージが既にインストールされています。

これのことですかね。

StorageQueueApp.csproj
  <ItemGroup>
    <PackageReference Include="Azure.Storage.Queues" Version="12.8.0" />
  </ItemGroup>

接続文字列を取得する

Azure CLI で取得します。

Azure Cloud Shell
$ export MY_STORAGE_CONNECTION_STRING=`az storage account show-connection-string -g learn-759f9aad-33f7-473a-9f8b-c3d324621976 --output tsv -n learn759f9aadstorage`

$ echo $MY_STORAGE_CONNECTION_STRING
DefaultEndpointsProtocol=https;EndpointSuffix=core.windows.net;AccountName=learn759f9aadstorage;AccountKey=xxxxxxxxxx7zxQ+aHniRpt5rkGHokcGz7a2zrJe5SKgSmIdH2jHgKbqGPOE5JcjKGIH2OV/yWotY+AStB3/gWA==;BlobEndpoint=https://learn759f9aadstorage.blob.core.windows.net/;FileEndpoint=https://learn759f9aadstorage.file.core.windows.net/;QueueEndpoint=https://learn759f9aadstorage.queue.core.windows.net/;TableEndpoint=https://learn759f9aadstorage.table.core.windows.net/

QueueClient を作成するコードを追加する

QueueClient クラスは、ストレージ キューとの通信を管理します。
QueueClient クラスを使うと、キューを作成し、キューとの間でメッセージを送受信できます。

ちなみに、QueueClinet はスレッドセーフなようです。
なのでアプリケーション全体で一つのインスタンスを使いまわせばよいみたい。

アプリケーションがやり取りするキューごとに、1 つの QueueClient オブジェクトを作成します。 そして、キューにアクセスする必要のあるコード内のすべてのメソッドに、その QueueClient インスタンスを渡します。 この QueueClient クラスはスレッドセーフなので、1 つのインスタンスをアプリケーション全体で使用することができます。

  1. コード エディターで Program.cs ファイルを開きます。
  2. Main メソッドの先頭に、次のコードを追加します。
Program.cs
    class Program
    {
        static async Task Main(string[] args)
        {
            // Add code to create QueueClient and Storage Queue Here
	    
+            string connectionString = Environment.GetEnvironmentVariable("MY_STORAGE_CONNECTION_STRING");
+            QueueClient queueClient = new QueueClient(connectionString, "newsqueue");

            bool exitProgram = false;
            while (exitProgram == false)

ストレージ アカウント キューを作成する

キューからメッセージを送受信する前に、キュー自体を作成する必要があります。 キューは、Azure portal、Azure CLI、Azure PowerShell から、またはコード内で作成できます。 このアプリケーションのサンプルでは、コードからキューを作成します。

ということでコードからキューを作成します。
以下の1文をProgram.csに追加します。

Program.cs
    class Program
    {
        static async Task Main(string[] args)
        {
            // Add code to create QueueClient and Storage Queue Here
            string connectionString = Environment.GetEnvironmentVariable("MY_STORAGE_CONNECTION_STRING");
            QueueClient queueClient = new QueueClient(connectionString, "newsqueue");
+            await queueClient.CreateIfNotExistsAsync();

            bool exitProgram = false;
            while (exitProgram == false)

演習 - メッセージをキューに追加する

メッセージを送信するためのコードを追加する

  1. Program.cs を開きます。
  2. SendMessageAsync メソッドを見つけます。
  3. NotImplementedException をスローする行を削除します。
  4. SendMessageAsync メソッドの先頭に次のコードを追加して、ユーザーからの NewsArticle を取得します。
Program.cs
        static async Task SendMessageAsync(QueueClient queueClient)
        {
-            throw new NotImplementedException();
+            Console.WriteLine("Enter headline: ");
+            string headline = Console.ReadLine();
+            Console.WriteLine("Enter location: ");
+            string location = Console.ReadLine();
+            NewsArticle article = new NewsArticle() { Headline = headline, Location = location };
        }
  1. キューに格納する NewsArticle オブジェクトをJSON にシリアル化し、SendMessageAsync メソッドを使用してメッセージをキューに送信します。
Program.cs
        static async Task SendMessageAsync(QueueClient queueClient)
        {
            Console.WriteLine("Enter headline: ");
            string headline = Console.ReadLine();
            Console.WriteLine("Enter location: ");
            string location = Console.ReadLine();
            NewsArticle article = new NewsArticle() { Headline = headline, Location = location };

+            string message = JsonSerializer.Serialize(article);
+            Response<SendReceipt> response = await queueClient.SendMessageAsync(message);
+            SendReceipt sendReceipt = response.Value;
        }
  1. メッセージを送信した際の応答に含まれていた SendReceipt に関する情報をコンソールに出力します。
Program.cs
        static async Task SendMessageAsync(QueueClient queueClient)
        {
            // Get input from user
            Console.WriteLine("Enter headline: ");
            string headline = Console.ReadLine();
            Console.WriteLine("Enter location: ");
            string location = Console.ReadLine();
            NewsArticle article = new NewsArticle() { Headline = headline, Location = location };

            // Build and send the message to the queue
            string message = JsonSerializer.Serialize(article);
            Response<SendReceipt> response = await queueClient.SendMessageAsync(message);
            SendReceipt sendReceipt = response.Value;

+            Console.WriteLine($"Message sent. Message id={sendReceipt.MessageId}  Expiration time={sendReceipt.ExpirationTime}");
+            Console.WriteLine();
        }

アプリケーションを実行する

  1. Cloud Shell で dotnet build コマンドを使用してアプリケーションをビルドします。
Azure Cloud Shell
$ dotnet build
  1. アプリケーションを実行します。
Azure Cloud Shell
$ dotnet run
  1. アプリケーションが起動したら、オプション 1 を選択してメッセージを送信し、お好みの見出しと場所を入力して、キューにメッセージを送信します。
Azure Cloud Shell
What operation would you like to perform?
  1 - Send message
  2 - Peek at the next message
  3 - Receive message
  X - Exit program
1

Enter headline: 
近所のネコの生態について
Enter location: 
日本
Message sent. Message id=5d5f677e-4162-4d3e-87c7-151da69ed3ca  Expiration time=12/25/2023 8:56:12 AM +00:00

What operation would you like to perform?
  1 - Send message
  2 - Peek at the next message
  3 - Receive message
  X - Exit program
X

結果を確認する

キューの確認は、Azure portal で Azure CLI を使用するか、Azure PowerShell を使用して行うことができます。
ここでは Azure CLI で確認します。

Azure Cloud Shell
$ az storage message peek --queue-name newsqueue --connection-string $MY_STORAGE_CONNECTION_STRING
Command group 'storage message' is in preview and under development. Reference and support levels: https://aka.ms/CLI_refstatus
[
  {
    "content": "{\"Headline\":\"\\u8FD1\\u6240\\u306E\\u30CD\\u30B3\\u306E\\u751F\\u614B\\u306B\\u3064\\u3044\\u3066\",\"Location\":\"\\u65E5\\u672C\"}",
    "dequeueCount": 0,
    "expirationTime": "2023-12-25T08:56:12+00:00",
    "id": "5d5f677e-4162-4d3e-87c7-151da69ed3ca",
    "insertionTime": "2023-12-18T08:56:12+00:00",
    "popReceipt": null,
    "timeNextVisible": null
  }
]

がっつりエンコードされていてわかりませんが、なにか入ったようです。

演習 - キューからメッセージを取得する

次のメッセージをクイック表示する

  1. Program.cs を開きます。
  2. PeekMessageAsync メソッドを見つけ、NotImplementedException をスローする行を削除します。
  3. メソッドに次のコードを追加します。 このコードは、キューの次のメッセージをクイック表示し、メッセージに関する情報を出力します。
Program.cs
        static async Task PeekMessageAsync(QueueClient queueClient)
        {
-            throw new NotImplementedException();
+            Response<PeekedMessage> response = await queueClient.PeekMessageAsync();
+            PeekedMessage message = response.Value;

+            Console.WriteLine($"Message id  : {message.MessageId}");
+            Console.WriteLine($"Inserted on : {message.InsertedOn}");
+            Console.WriteLine("We are only peeking at the message, so another consumer could dequeue this message");
        }

メッセージの受信と処理

  1. ReceiveMessageAsync メソッドを見つけ、NotImplementedException をスローする行を削除します。
  2. ReceiveMessageAsync メソッドの先頭に次のコードを追加して、キューからメッセージを取得します。
Program.cs
        static async Task ReceiveMessageAsync(QueueClient queueClient)
        {
-            throw new NotImplementedException();
+            Response<QueueMessage> response = await queueClient.ReceiveMessageAsync();
+            QueueMessage message = response.Value;
        }
  1. 次のコードを追加します。JSON 形式の生メッセージの本文など、受信したメッセージに関するプロパティを出力します。
Program.cs
        static async Task ReceiveMessageAsync(QueueClient queueClient)
        {
            Response<QueueMessage> response = await queueClient.ReceiveMessageAsync();
            QueueMessage message = response.Value;

+            Console.WriteLine($"Message id    : {message.MessageId}");
+            Console.WriteLine($"Inserted on   : {message.InsertedOn}");
+            Console.WriteLine($"Message (raw) : {message.Body}");
        }
  1. メッセージの内容を、自分のコード内で使用できるオブジェクトにデシリアライズするため、QueueMessage オブジェクトの Body プロパティに ToObjectFromJson メソッドを追加します。
Program.cs
        static async Task ReceiveMessageAsync(QueueClient queueClient)
        {
            Response<QueueMessage> response = await queueClient.ReceiveMessageAsync();
            QueueMessage message = response.Value;

            Console.WriteLine($"Message id    : {message.MessageId}");
            Console.WriteLine($"Inserted on   : {message.InsertedOn}");
            Console.WriteLine($"Message (raw) : {message.Body}");

+            NewsArticle article = message.Body.ToObjectFromJson<NewsArticle>();
+            Console.WriteLine("News Article");
+            Console.WriteLine($"-  Headline : {article.Headline}");
+            Console.WriteLine($"-  Location : {article.Location}");
        }
  1. 最後に、メッセージの処理を終了するときに、他のコンシューマーによって処理されないよう、キューからメッセージを削除します。
Program.cs
        static async Task ReceiveMessageAsync(QueueClient queueClient)
        {
            Response<QueueMessage> response = await queueClient.ReceiveMessageAsync();
            QueueMessage message = response.Value;

            Console.WriteLine($"Message id    : {message.MessageId}");
            Console.WriteLine($"Inserted on   : {message.InsertedOn}");
            Console.WriteLine($"Message (raw) : {message.Body}");

            NewsArticle article = message.Body.ToObjectFromJson<NewsArticle>();
            Console.WriteLine("News Article");
            Console.WriteLine($"-  Headline : {article.Headline}");
            Console.WriteLine($"-  Location : {article.Location}");

+            Console.WriteLine("The processing for this message is just printing it out, so now it will be deleted");
+            await queueClient.DeleteMessageAsync(message.MessageId, message.PopReceipt);
+            Console.WriteLine($"Message deleted");
        }
  1. Program.cs を保存します。

アプリケーションを実行する

  1. アプリケーションをビルドします。
Azure Cloud Shell
$ dotnet build
  1. アプリケーションを実行します。
Azure Cloud Shell
$ dotnet run
  1. キューにメッセージを追加したり、表示したりしましょう。
Azure Cloud Shell
What operation would you like to perform?
  1 - Send message
  2 - Peek at the next message
  3 - Receive message
  X - Exit program
1

Enter headline: 
近所のネコに新しい仲間が増えました
Enter location: 
日本
Message sent. Message id=1c04af1a-8686-4fbe-af9e-94e8c24d29d0  Expiration time=12/25/2023 9:11:04 AM +00:00

What operation would you like to perform?
  1 - Send message
  2 - Peek at the next message
  3 - Receive message
  X - Exit program
2

Message id  : 5d5f677e-4162-4d3e-87c7-151da69ed3ca
Inserted on : 12/18/2023 8:56:12 AM +00:00
We are only peeking at the message, so another consumer could dequeue this message
What operation would you like to perform?
  1 - Send message
  2 - Peek at the next message
  3 - Receive message
  X - Exit program
3

Message id    : 5d5f677e-4162-4d3e-87c7-151da69ed3ca
Inserted on   : 12/18/2023 8:56:12 AM +00:00
Message (raw) : {"Headline":"\u8FD1\u6240\u306E\u30CD\u30B3\u306E\u751F\u614B\u306B\u3064\u3044\u3066","Location":"\u65E5\u672C"}
News Article
-  Headline : 近所のネコの生態について
-  Location : 日本
The processing for this message is just printing it out, so now it will be deleted
Message deleted
What operation would you like to perform?
  1 - Send message
  2 - Peek at the next message
  3 - Receive message
  X - Exit program
3

Message id    : 1c04af1a-8686-4fbe-af9e-94e8c24d29d0
Inserted on   : 12/18/2023 9:11:04 AM +00:00
Message (raw) : {"Headline":"\u8FD1\u6240\u306E\u30CD\u30B3\u306B\u65B0\u3057\u3044\u4EF2\u9593\u304C\u5897\u3048\u307E\u3057\u305F","Location":"\u65E5\u672C"}
News Article
-  Headline : 近所のネコに新しい仲間が増えました
-  Location : 日本
The processing for this message is just printing it out, so now it will be deleted
Message deleted
What operation would you like to perform?
  1 - Send message
  2 - Peek at the next message
  3 - Receive message
  X - Exit program

なんだか良さそう!

おわりに

今回はすんなり動きました。
そしてSDK使うので簡単で良いですね。
それではまた。

Discussion