在Azure服务总线上的死信队列中完成消息

在Azure服务总线上的死信队列中完成消息,azure,azureservicebus,azure-servicebus-queues,Azure,Azureservicebus,Azure Servicebus Queues,我希望能够从死信队列中删除所选邮件 这是如何实现的 我经常会出错: 无法完成操作,因为ReceiveContext为Null 我已经尝试了我能想到和读到的每一种方法,我现在的处境如下: public void DeleteMessageFromDeadletterQueue<T>(string queueName, long sequenceNumber) { var client = GetQueueClient(queueName, true);

我希望能够从死信队列中删除所选邮件

这是如何实现的

我经常会出错:

无法完成操作,因为ReceiveContext为Null

我已经尝试了我能想到和读到的每一种方法,我现在的处境如下:

public void DeleteMessageFromDeadletterQueue<T>(string queueName, long sequenceNumber)
        {
     var client = GetQueueClient(queueName, true);
                var messages = GetMessages(client);
                foreach(var m in messages)
                {
                    if(m.SequenceNumber == sequenceNumber)
                    {
                        m.Complete();
                    }
                    else
                    {
                        m.Abandon();
                    }
                }
}

/// <summary>
        /// Return a list of all messages in a Queue
        /// </summary>
        /// <param name="client"></param>
        /// <returns></returns>
        private IEnumerable<BrokeredMessage> GetMessages(QueueClient client)
        {
            var peekedMessages = client.PeekBatch(0, peekedMessageBatchCount).ToList();
            bool getmore = peekedMessages.Count() == peekedMessageBatchCount ? true : false;

            while (getmore)
            {
                var moreMessages = client.PeekBatch(peekedMessages.Last().SequenceNumber, peekedMessageBatchCount);
                peekedMessages.AddRange(moreMessages);
                getmore = moreMessages.Count() == peekedMessageBatchCount ? true : false;
            }

            return peekedMessages;
        }
public void DeleteMessageFromDeadletterQueue(字符串queueName,长序列号)
{
var client=GetQueueClient(queueName,true);
var messages=GetMessages(客户端);
foreach(消息中的var m)
{
如果(m.SequenceNumber==SequenceNumber)
{
m、 完全();
}
其他的
{
m、 放弃();
}
}
}
/// 
///返回队列中所有消息的列表
/// 
/// 
/// 
私有IEnumerable GetMessages(QueueClient客户端)
{
var peekedMessages=client.PeekBatch(0,peekedMessageBatchCount).ToList();
bool getmore=peekedMessages.Count()==peekedMessageBatchCount?true:false;
while(获取更多)
{
var moreMessages=client.PeekBatch(peekedMessages.Last().SequenceNumber,peekedMessageBatchCount);
peekedMessages.AddRange(更多消息);
getmore=moreMessages.Count()==peekedMessageBatchCount?true:false;
}
返回偷看信息;
}

不确定为什么这看起来是一项如此困难的任务。

这里的问题是,您调用了PeekBatch,它返回了刚刚查看的消息。没有可用于完成或放弃消息的接收上下文。Peek和PeekBatch操作仅返回消息,并且根本不锁定它们,即使receivedMode设置为PeekLock。这主要是为了浏览队列,但你不能对它们采取行动。请注意,放弃和完成状态的文档“必须仅在使用在Peek Lock ReceiveMode下操作的接收器接收到的消息上调用。”此处不清楚,但Peek和Peek批处理操作不计入此项,因为它们实际上没有接收上下文。这就是当您尝试调用放弃时失败的原因。如果你真的找到了你要找的那个,当你调用Complete时,它会抛出一个不同的错误

您要做的是在PeekBatch ReceiveMode中使用ReceiveBatch操作。这实际上会将一批消息拉回来,然后当您查看它们以找到您想要的消息时,您实际上可以影响消息的完整性。当您启动放弃按钮时,它会立即将您不想要的消息释放回队列

如果你的死信队列很小,通常情况下,这不会很糟糕。如果它真的很大,那么采用这种方法并不是最有效的。您将死信队列视为一堆,并对其进行挖掘,而不是“按顺序”处理消息。这在处理需要手动干预的死信队列时并不少见,但是如果您有很多这样的队列,那么最好让一些东西将死信队列处理到另一种类型的存储中,这样您可以更容易地查找和销毁邮件,但仍然可以重新创建可以推送到其他队列重新处理的消息


如果您手动使用死字,可能还有其他选项,例如使用“延迟”。看

我没有接受MikeWo的建议,因为当我用ReceiveMode.PeekLock实例化DLQ QueueClient并用ReceiveBatch拉取消息时,我使用的是Receive/ReceiveBatch的版本,通过其序列号请求消息

[旁白:在我的应用程序中,我查看所有消息并列出它们,然后让另一个处理程序根据特定的序列号将死信消息重新排入主队列…]

但是在DLQClient上调用Receive(long sequenceNumber)或ReceiveBatch(IEnumerable sequenceNumber)总是引发异常,“未能锁定一个或多个指定的消息。该消息不存在。”(即使我只通过了1并且它肯定在队列中)

此外,由于不清楚的原因,使用ReceiveBatch(int messageCount),无论messageCount使用什么值,始终只返回队列中的下一条1消息

最终对我起作用的是:

QueueClient queueClient, deadLetterClient;
GetQueueClients(qname, ReceiveMode.PeekLock, out queueClient, out deadLetterClient);

BrokeredMessage msg = null;
var mapSequenceNumberToBrokeredMessage = new Dictionary<long, BrokeredMessage>();
while (msg == null)
{
#if UseReceive
    var message = deadLetterClient.Receive();
#elif UseReceiveBatch
    var messageEnumerable = deadLetterClient.ReceiveBatch(CnCountOfMessagesToPeek).ToList();
    if ((messageEnumerable == null) || (messageEnumerable.Count == 0))
        break;
    else if (messageEnumerable.Count != 1)
        throw new ApplicationException("Invalid expectation that there'd always be only 1 msg returned by ReceiveBatch");

    // I've yet to get back more than one in the deadletter queue, but... 
    var message = messageEnumerable.First();
#endif
    if (message.SequenceNumber == lMessageId)
    {
        msg = message;
        break;
    }
    else if (mapSequenceNumberToBrokeredMessage.ContainsKey(message.SequenceNumber))
    {
        // this means it's started the list over, so we didn't find it...
        break;
    }
    else
        mapSequenceNumberToBrokeredMessage.Add(message.SequenceNumber, message);
    message.Abandon();
}                        

if (msg == null)
    throw new ApplicationException("Unable to find a message in the deadletter queue with the SequenceNumber: " + msgid);

var strMessage = GetMessage(msg);
var newMsg = new BrokeredMessage(strMessage);
queueClient.Send(newMsg);

msg.Complete();
QueueClient,deadLetterClient;
GetQueueClient(qname、ReceiveMode.PeekLock、out queueClient、out deadLetterClient);
BrokeredMessage msg=null;
var mapSequenceNumberToBrokeredMessage=新字典();
while(msg==null)
{
#如果用户接收
var message=deadLetterClient.Receive();
#elif UseReceiveBatch
var messageEnumerable=deadLetterClient.ReceiveBatch(cncountofmessagesgestopeek.ToList();
if((messageEnumerable==null)| |(messageEnumerable.Count==0))
打破
else if(messageEnumerable.Count!=1)
抛出新的ApplicationException(“ReceiveBatch始终只返回1条消息的无效期望”);
//我还没有在死信队列中找到多个,但是。。。
var message=messageEnumerable.First();
#恩迪夫
if(message.SequenceNumber==lMessageId)
{
msg=消息;
打破
}
else if(mapSequenceNumberToBrokeredMessage.ContainsKey(message.SequenceNumber))
{
//这意味着它重新开始了列表,所以我们没有找到它。。。
打破
}
其他的
mapSequenceNumberToBrokeredMessage.Add(message.SequenceNumber,message);
消息。放弃();
}                        
如果(msg==null)
抛出新的ApplicationException(“无法在死信队列中找到具有