Как быстро закрыть все элементы Microsoft SQL Server Service Broker?

У нас есть приложение, которое создает очереди и службы в SQL Server, используя Service Broker для обработки связи с базой данных. Приложение использует эти службы и правильно отправляет/получает сообщения, но теперь я хочу протестировать фазу инициализации этого приложения (оно создает брокера, а также хранимые процессы, которые работают за кулисами). По сути, мне нужно сбрасывать элементы брокера с некоторой частотой, и сейчас это действительно очень медленно.

Я могу изменить способ, которым приложение создает элементы брокера, если это поможет, но этот вопрос больше связан с отключением всего.

Код, который я использую для закрытия брокера:

receive * from [dbo].[notify_initiator_queue]
alter queue [dbo].[notify_initiator_queue] with status = OFF
drop service [//DBNotifyService-Initiator]
drop queue [dbo].[notify_initiator_queue]
drop message types, contacts, etc...

Это зависает на некоторое время в «службе удаления [//XF/DBNotifyService-Initiator]». Есть ли более быстрый способ закрыть и удалить все или некоторые элементы сервисного брокера?

Спасибо!

==Обновление==

Хорошо, мне потребовалось некоторое время, но ответ ниже действительно решил проблему. Я хотел уточнить для всех, у кого может быть проблема.

Мое приложение правильно закрыло все службы, очереди, контракты и сообщения. На закрытие сервисов ушла целая вечность, потому что в приложении была куча открытых разговоров из-за ошибки. Эти разговоры создавались, использовались для отправки сообщения, а затем закрывались с помощью:

END CONVERSATION @conversation with cleanup

Бит «с очисткой» закрывает только локальный конец диалога (подумайте, он позволяет серверу очищать любые диалоги, которые могли быть ошибочными на другом конце). Он не закрывает другой конец службы отправки, поэтому разговоры остаются открытыми. Обычные разговоры следует заканчивать:

END CONVERSATION @conversation

Это исправило ошибку приложения. Однако у меня было несколько миллионов неработающих разговоров в БД. Я мог бы удалить базу данных, как обычный человек, или я мог бы попытаться выяснить, как их закрыть. Чтобы закрыть их все по одному требуется:

declare @conversation uniqueidentifier 
while exists (select top 1 conversation_handle from sys.transmission_queue ) 
begin 
  set @conversation = (select top 1 conversation_handle from sys.transmission_queue )
  end conversation @conversation with cleanup 
end

Это занимает несколько мс на соединение (очень медленно для миллионов). Если бы я хотел закрыть их все очень быстро, используйте ответ ниже и запустите модифицированную команду:

ALTER DATABASE [" + target.getTargetDbName() + "] SET NEW_BROKER WITH ROLLBACK IMMEDIATE;

Немедленный с откатом отключает все соединения, не позволяя им гарантировать фиксацию. В документации говорится: «Все незавершенные транзакции будут отменены, а любые другие подключения к образцу базы данных AdventureWorks2008R2 будут немедленно отключены». http://msdn.microsoft.com/en-us/library/bb522682.aspx

Службы сейчас очень быстро отключаются, ошибка и открытые соединения исчезли.


person Noah    schedule 03.08.2011    source источник


Ответы (1)


Причина медленная, вероятно, заключается в том, что эти элементы заблокированы блокировкой SCH-S, потому что они используются, что предотвращает ваши операторы удаления. Типичным виновником являются активированные процедуры, работающие в фоновом режиме. Это можно быстро выяснить, проверив причины блокировки Activity Monitor или просмотрев < a href="http://msdn.microsoft.com/en-us/library/ms177648.aspx">sys.dm_exec_requests. Выполнение активированных процедур можно увидеть в sys.dm_broker_activated_tasks.

В качестве обходного пути вы можете попробовать ALTER DATABASE SET NEW_BROKER, он удалит все существующие разговоры, но не очереди/услуги/контракты/типы сообщений. Это также изменит текущую базу данных service_broker_instance_id (важно, если вы использовали ее в маршрутах). При сбросе всех диалогов активированные процедуры должны завершиться сами (если они правильно написаны).

Но я бы рекомендовал другой подход. Вместо того, чтобы ваш тест повторно использовал одну и ту же базу данных снова и снова и обрабатывал все ложные сбои на этапе «отключения», вы всегда должны начинать с чистой базы данных и запускать сценарий развертывания на чистой базе данных. Таким образом, вам не нужен код «удаления». См. раздел Контроль версий и ваша база данных. Используйте резервную копию чистой базы данных и всегда начинайте с нее, восстанавливайте ее и развертывайте свое приложение, а затем запускайте проверочные тесты.

person Remus Rusanu    schedule 03.08.2011
comment
Спасибо всем за хорошие предложения, были некоторые потоки очереди, которые не закрывались должным образом, поэтому я смог найти способ справиться с открытыми соединениями. Что касается резервной копии БД - хорошая идея, но мы хотим, чтобы тест мог работать на любой БД, а не только на выделенном тестере. Спасибо. - person Noah; 04.08.2011
comment
ALTER DATABASE SET NEW_BROKER, будут удалены все существующие диалоги... - да, но не все триггеры, сервисные контракты, сервисные очереди, конечные точки и другие возможные вещи, принадлежащие сервис-брокеру. - person Marcus; 29.08.2018