Azure Queue Storage 是一个存储大量消息的队列存储服务。工作中,我们有时会遇到这么样的需求,当某个业务操作触发一个事件,而后让另一个系统对触发的这个事件进行处理,那么,这里的话可以采用配置一个 hook ,将截取到的这个消息存储到这个 Queues 消息队列里面,而后另一个系统可以采用新进新出的规则取获取这个消息,通过消息内容中的数据做出一系列的操作,而后删除这个消息。
项目准备
创建项目
还是在这个 GitHub 中项目(AzureStorageConsoleDemo)里面新建一个 AzureQueueDemo
文件夹,在文件夹中创建类文件 StorageQueuesHelp.cs
,安装 NuGet 包 Azure.Storage.Queues
。
StorageQueuesHelp 获取链接字符串
在 StorageQueuesHelp.cs
中键入如下代码以获取配置文件连接字符串。
using Azure.Storage.Queues;
using Microsoft.Extensions.Configuration;
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
namespace AzureStorageConsoleDemo.AzureQueueDemo
{
class StorageQueuesHelp
{
/// <summary>
/// Storage 连接字符串
/// </summary>
public string StorageConnectionString { get; set; }
/// <summary>
/// 初始化程序配置文件
/// </summary>
/// <returns>StorageTableHelp</returns>
public static StorageQueuesHelp LoadAppSettings()
{
IConfigurationRoot configRoot = new ConfigurationBuilder().AddJsonFile("Settings.json").Build();
StorageQueuesHelp appSettings = configRoot.Get<StorageQueuesHelp>();
return appSettings;
}
}
}
Queues 操作
关于 Queue 的应用操作有很多,这里根据常用的几类进行总结如下。
创建队列
这里创建一个 Queues ,返回的是一个 QueueClient
,可以通过 QueueClient
对消息队列的进一步操作,如 CRUD 等。在 StorageQueuesHelp.cs
中键入如下代码以获取配置文件连接字符串。
/// <summary>
/// 创建一个 Queues
/// </summary>
/// <param name="queuesName">Queues 的名称</param>
/// <returns>QueueClient</returns>
public static async Task<QueueClient> CreateQueueClientAsync(string queuesName)
{
string connectionString = LoadAppSettings().StorageConnectionString;
QueueClient queueClient = new QueueClient(connectionString, queuesName);
await queueClient.CreateAsync();
return queueClient;
}
使用示例:
static async Task Main(string[] args)
{
// 声明一个 Queues 的名称
string queueName = "queues" + Guid.NewGuid().ToString().Substring(0, 5);
// 传入一个 Queues 的名称 返回 QueueClient 通过 QueueClient 可以对 Queues 进行操作
QueueClient queueClient1 = await StorageQueuesHelp.CreateQueueClientAsync(queueName);
}
向队列中添加消息
在 StorageQueuesHelp.cs
中键入如下代码以获取配置文件连接字符串。
/// <summary>
/// 向队列中插入一条消息 默认永不过期
/// </summary>
/// <param name="theQueue">QueueClient</param>
/// <param name="newMessage">消息字符串</param>
/// <returns></returns>
public static async Task<SendReceipt> InsertMessageAsync(QueueClient theQueue, string newMessage, bool isInvalid = false)
{
// 检测队列是否创建,如果没有创建则创建,否则不做操作
await theQueue.CreateIfNotExistsAsync();
// 向队列发送一条新的消息
SendReceipt sendReceipt;
if (isInvalid)
{
// 默认生存周期为 7 天
sendReceipt = await theQueue.SendMessageAsync(newMessage);
}
else
{
// 永不过期消息
sendReceipt = await theQueue.SendMessageAsync(newMessage, default, TimeSpan.FromSeconds(-1), default);
}
return sendReceipt;
}
使用示例:
static async Task Main(string[] args)
{
// 声明一个 Queues 的名称
string queueName = "queues" + Guid.NewGuid().ToString().Substring(0, 5);
// 传入一个 Queues 的名称 返回 QueueClient 通过 QueueClient 可以对 Queues 进行操作
QueueClient queueClient = await StorageQueuesHelp.CreateQueueClientAsync(queueName);
// 插入一条消息到队列中
SendReceipt sendReceipt = await StorageQueuesHelp.InsertMessageAsync(queueClient,"一条消息",true);
}
更新队列中的消息
如果需要更新队列中的一条消息,可以使用 queueClient.UpdateMessageAsync()
方法来处理,使用方式如下所示。
static async Task Main(string[] args)
{
// 声明一个 Queues 的名称
string queueName = "queues" + Guid.NewGuid().ToString().Substring(0, 5);
// 传入一个 Queues 的名称 返回 QueueClient 通过 QueueClient 可以对 Queues 进行操作
QueueClient queueClient = await StorageQueuesHelp.CreateQueueClientAsync(queueName);
// 插入一条消息到队列中
SendReceipt sendReceipt = await StorageQueuesHelp.InsertMessageAsync(queueClient,"第一条消息",true);
// 更新刚刚插入成功的一条消息
await queueClient.UpdateMessageAsync(sendReceipt.MessageId, sendReceipt.PopReceipt, "第一条消息已更新");
}
查看队列中的消息
即查看队列中的消息,但 所被查看的消息依旧存在于队列之中 。示例代码如下所示。
static async Task Main(string[] args)
{
// 声明一个 Queues 的名称
string queueName = "queues" + Guid.NewGuid().ToString().Substring(0, 5);
// 传入一个 Queues 的名称 返回 QueueClient 通过 QueueClient 可以对 Queues 进行操作
QueueClient queueClient = await StorageQueuesHelp.CreateQueueClientAsync(queueName);
// 查看队列中的消息 PeekMessagesAsync()中的参数为最大为 32 ,如果不设置参数,那么就取队列中的第一个消息
PeekedMessage[] peekedMessages = await queueClient.PeekMessagesAsync(maxMessages: 10);
//遍历获取的消息
foreach (PeekedMessage peekedMessage in peekedMessages)
{
// 显示消息
Console.WriteLine($"消息: {peekedMessage.MessageText}");
}
}
获取队列中的消息
和查看队列中的消息类似,但 所被查看的消息将会在默认超时时间内在队列中不可见1 。示例代码如下所示。
static async Task Main(string[] args)
{
// 声明一个 Queues 的名称
string queueName = "queues" + Guid.NewGuid().ToString().Substring(0, 5);
// 传入一个 Queues 的名称 返回 QueueClient 通过 QueueClient 可以对 Queues 进行操作
QueueClient queueClient = await StorageQueuesHelp.CreateQueueClientAsync(queueName);
// 从队列中获取一条小溪消息 获取的消息将会在队列中 30 秒不可见
QueueMessage[] message = await queueClient.ReceiveMessagesAsync();
Console.WriteLine($"消息: {message[0].MessageText}");
// 从队列中获取最多 10 条消息 获取的消息将会在队列中 30 秒不可见
QueueMessage[] messages = await queueClient.ReceiveMessagesAsync(maxMessages: 10);
foreach (var peekedMessage in messages)
{
Console.WriteLine($"消息: {peekedMessage.MessageText}");
}
}
从队列中删除消息
当从队列中获取一条消息后,需要对这条消息进行一系列程序操作,等操作完毕之后,需要将这条消息从队列中删除,这里可以通过调用 DeleteMessageAsync
从队列中删除该消息。
static async Task Main(string[] args)
{
// 声明一个 Queues 的名称
string queueName = "queues" + Guid.NewGuid().ToString().Substring(0, 5);
// 传入一个 Queues 的名称 返回 QueueClient 通过 QueueClient 可以对 Queues 进行操作
QueueClient queueClient = await StorageQueuesHelp.CreateQueueClientAsync(queueName);
// 从队列中获取一条小溪消息 获取的消息将会在队列中 30 秒不可见
QueueMessage[] message = await queueClient.ReceiveMessagesAsync();
// 删除从队列中检索出来的这条消息
await queueClient.DeleteMessageAsync(message[0].MessageId, message[0].PopReceipt);
}
情景回顾:
记得工作中有一次我拿到一个项目,需要获取一个消息,而后对这个消息经过操作处理后再删除,否则在处理下一个消息的时候还会重复获取这条消息。于是这个项目在获取这条消息之后,在处理这条消息之前直接就将这条消息给删除掉了,于是,这么就会出现一种情况,程序在处理这条消息的时候并未成功处理这条消息,但是这条消息却被从队列中删除掉了,那么,怎么办呢?
建议提示:
像这种情况,大部分程序员都会想到,我可以在操作处理这条消息成功过后再删除这条消息呀!对的,没错,这样能够解决这个问题。但是还有一个问题,如果让程序在操作处理消息之后再进行删除消息操作,那么当每一次获取这条消息都不能成功处理这条消息,而程序继续获取这条消息,是不是程序就是锁在这条消息处而不能继续运行下一条消息了呢?
其实,可以调用DequeueCount
来获取这条消息出队列多少次了,当程序重复处理这条消息重复达到多少次以后我们可以直接将这条消息删除掉并报错处理,让程序员工程师对这条消息进行单独操作。如下示例所示:
long msgCount=message[0].DequeueCount; // 获取这条消息出队列次数
删除队列
为了节约账户所花费的成本,空队列可以选择删除,在需要的时候再创建即可,但是切记在删除之前还是需要跟你的客户或者老板沟通好,是否确定要删除这个队列哦。
static async Task Main(string[] args)
{
string queueName = "queues" + Guid.NewGuid().ToString().Substring(0, 5);
QueueClient queueClient = await StorageQueuesHelp.CreateQueueClientAsync(queueName);
// 删除这个队列
Console.WriteLine($"删除队列: {queueClient.Name}");
await queueClient.DeleteAsync();
Console.ReadLine();
}
The Ended
如果你还想要领略一下 Azure Queue Storage
的那些花式操作,你可以访问微软的 官方教程 。我这里总结的就这些,因为工作中就这么用的,喜欢的可以 点各赞、收个藏 。
指定相对于服务器时间的新可见性超时值(以秒为单位)。 默认值为 30 秒。 ↩︎