Как подписаться на очередь MSMQ, но только «заглянуть» на сообщение в .NET?
-
02-10-2019 - |
Вопрос
У нас есть настройка очереди MSMQ, которая получает сообщения и обрабатывается приложением. Мы хотели бы, чтобы еще один процесс подпишился на очередь и просто прочитал сообщение и войдите в систему.
У меня уже есть это на месте, проблема в том, что она постоянно заглядывает в очередь. ЦП на сервере, когда он работает, составляет около 40%. MQSVC.Exe работает на уровне 30%, и это приложение работает на уровне 10%. Я бы предпочел что -то, что просто ждет сообщения, получает уведомление об этом, а затем регистрирует его без постоянного опроса на сервере.
Dim lastid As String
Dim objQueue As MessageQueue
Dim strQueueName As String
Public Sub Main()
objQueue = New MessageQueue(strQueueName, QueueAccessMode.SendAndReceive)
Dim propertyFilter As New MessagePropertyFilter
propertyFilter.ArrivedTime = True
propertyFilter.Body = True
propertyFilter.Id = True
propertyFilter.LookupId = True
objQueue.MessageReadPropertyFilter = propertyFilter
objQueue.Formatter = New ActiveXMessageFormatter
AddHandler objQueue.PeekCompleted, AddressOf MessageFound
objQueue.BeginPeek()
end main
Public Sub MessageFound(ByVal s As Object, ByVal args As PeekCompletedEventArgs)
Dim oQueue As MessageQueue
Dim oMessage As Message
' Retrieve the queue from which the message originated
oQueue = CType(s, MessageQueue)
oMessage = oQueue.EndPeek(args.AsyncResult)
If oMessage.LookupId <> lastid Then
' Process the message here
lastid = oMessage.LookupId
' let's write it out
log.write(oMessage)
End If
objQueue.BeginPeek()
End Sub
Решение
Thread.sleep (10) между итерациями Peek может сэкономить вам кучу циклов.
Единственный другой вариант, о котором я могу подумать, - это построить журнал в приложении для чтения очередей.
Другие советы
Вы пробовали использовать Msmqevent.arived Чтобы отслеживать сообщения?
Прибывшее событие объекта MSMQEVENT запускается, когда был вызван метод MSMQQUEUE.ENABLENOTICATIATIONE экземпляра объекта MSMQQUEUE, представляющего открытую очередь, и сообщение найдено или прибывает в соответствующую позицию в очереди.
Там нет API, который бы позволит вам заглянуть на каждое сообщение только один раз.
Проблема в том, что BeginPeek
немедленно выполняет свой обратный вызов, если в очереди уже есть сообщение. Поскольку вы не удаляете сообщение (это заглядывать В конце концов, не получай!), Когда ваш обратный вызов снова начинает взглянуть, процесс начинается все сначала, так что MessageFound
Бежит почти постоянно.
Ваши лучшие варианты - регистрировать сообщения в писателе или читателе. Журналирование Будет работать в течение коротких периодов (если вы заботитесь только о полученных сообщениях), но не является долгосрочным решением:
В то время как накладные расходы на производительность извлечения сообщений из очереди, настроенной для журнала, составляет всего на 20% больше, чем извлечение сообщений без журнала, реальная стоимость - это неожиданные проблемы, вызванные, когда неконтролируемая служба MSMQ выходит из памяти, или машина выходит из диска. Космос
Это работает для меня. Он блокирует поток в ожидании сообщения. Каждый цикл цикла проверяет член класса _bServiceRunning
Чтобы увидеть, должна ли поток прервать.
private void ProcessMessageQueue(MessageQueue taskQueue)
{
// Set the formatter to indicate body contains a binary message:
taskQueue.Formatter = new BinaryMessageFormatter();
// Specify to retrieve selected properties.
MessagePropertyFilter myFilter = new MessagePropertyFilter();
myFilter.SetAll();
taskQueue.MessageReadPropertyFilter = myFilter;
TimeSpan tsQueueReceiveTimeout = new TimeSpan(0, 0, 10); // 10 seconds
// Monitor the MSMQ until the service is stopped:
while (_bServiceRunning)
{
rxMessage = null;
// Listen to the queue for the configured duration:
try
{
// See if a message is available, and if so remove if from the queue if any required
// web service is available:
taskQueue.Peek(tsQueueReceiveTimeout);
// If an IOTimeout was not thrown, there is a message in the queue
// Get all the messages; this does not remove any messages
Message[] arrMessages = taskQueue.GetAllMessages();
// TODO: process the message objects here;
// they are copies of the messages in the queue
// Note that subsequent calls will return the same messages if they are
// still on the queue, so use some structure defined in an outer block
// to identify messages already processed.
}
catch (MessageQueueException mqe)
{
if (mqe.MessageQueueErrorCode == MessageQueueErrorCode.IOTimeout)
{
// The peek message time-out has expired; there are no messages waiting in the queue
continue; // at "while (_bServiceRunning)"
}
else
{
ErrorNotification.AppLogError("MSMQ Receive Failed for queue: " + mqs.Name, mqe);
break; // from "while (_bServiceRunning)"
}
}
catch (Exception ex)
{
ErrorNotification.AppLogError("MSMQ Receive Failed for queue: " + mqs.Name, ex);
break; // from "while (_bServiceRunning)"
}
}
} // ProcessMessageQueue()
ИМХО, вы должны просто включить журналинг на очередь. Тогда вам гарантируется, что копия содержится из всех сообщений, которые были привержены очереди, и это просто не так с вашей трудовой попыткой сделать ваш собственный механизм для регистрации всего этого.
Гораздо, намного проще и более надежным является регистрация и удаление журналированных сообщений на запланированной основе, если вы хотите что -то более легко читаемое, чем сама очередь (и я, конечно, хотел бы этого). Тогда не имеет значения, насколько быстро или нет процесс, вам нужно получить сообщения только один раз, и в целом это гораздо лучший способ решить проблему.