読者です 読者をやめる 読者になる 読者になる

しばやん雑記

ASP.NET とメイドさんが大好きなフリーランスのプログラマーのブログ

Azure Storage Queue で遅延キューを利用する

あまり Azure で使っているのを見たことはないのですが、Azure Storage Queue でも指定した時間が経過した後に Dequeue 可能になるようがメッセージを追加することが出来ます。

.NET Storage SDK には制約が書いてなかったですが、REST API のリファレンスにはありました。

Optional. If specified, the request must be made using an x-ms-version of 2011-08-18 or newer. If not specified, the default value is 0. Specifies the new visibility timeout value, in seconds, relative to server time. The new value must be larger than or equal to 0, and cannot be larger than 7 days. The visibility timeout of a message cannot be set to a value later than the expiry time. visibilitytimeout should be set to a value smaller than the time-to-live value.

Put Message | Microsoft Docs

API Version が 2011-08-18 より新しい必要がありますが、最新の SDK を使っていれば問題ないです。

そして試してはいないですが、秒単位で最大 7 日まで指定可能です。注意点としては TTL の値より小さくしないといけないようです。

実際に Queue にメッセージを追加して動作を確認してみます。違いは AddMessage を呼び出すときに initialVisibilityDelay を指定するかどうかだけです。TimeSpan なので秒以下も指定できますが無視されます。

var storageAccount = CloudStorageAccount.Parse("DefaultEndpointsProtocol=https;AccountName=***;AccountKey=***");
var queueClient = storageAccount.CreateCloudQueueClient();

var queue = queueClient.GetQueueReference("sample");

queue.CreateIfNotExists();

// そのままメッセージを追加する
queue.AddMessage(new CloudQueueMessage("kosmosebi"));

// initialVisibilityDelay として 30 秒を指定して追加する
queue.AddMessage(new CloudQueueMessage("statemachine"), initialVisibilityDelay: TimeSpan.FromSeconds(30));

Queue に追加されたメッセージは Azure Storage Explorer を使うと簡単に確認できます。同じような名前で古いアプリもあるので、間違えないように以下のリンクを貼っておきました。*1

Microsoft Azure Storage Explorer

Azure Storage Explorer では非表示状態になっているメッセージが存在する場合には、左下に表示されている数がずれるようになってます。

この場合は通常のメッセージが 1 つと非表示状態のメッセージが 1 つ存在しています。

f:id:shiba-yan:20170328143731p:plain

大体 30 秒が経過した後に読み込み直すと、2 つのメッセージが表示されます。

2 つのメッセージの Insertion Time が同じになっていることから、後から追加されたわけではないことが分かりますね。これで手軽に処理を遅らせることが出来ます。

f:id:shiba-yan:20170328143813p:plain

アプリケーションやワーカーなどで Thread.Sleep などで無駄な待ちをさせることなく、5 秒だけ処理を遅らせたいみたいな場合には、遅延キューを使えば簡単に仕組みを変えずに実現できます。

メッセージ単位で initialVisibilityDelay を指定すると、当然ながら FIFO が崩れます。注意したいです。