Выбрать один экземпляр веб-приложения для выполнения задачи, вызванной внешним событием? - PullRequest
2 голосов
/ 04 марта 2010

У меня есть приложение ASP.NET, работающее на нескольких веб-серверах IIS6 с серверной частью базы данных SQL Server 2005.

Мне нужно:

  1. отслеживать базу данных на предмет завершения события внешнего задания, а затем

  2. только один экземпляр веб-приложения передает некоторую информацию веб-службе

Для (1) кажется, что SqlDependency был бы лучшим подходом (или просто простым старым опросом). Каждый экземпляр веб-приложения регистрирует такую ​​зависимость при запуске. (Я не хочу настраивать «главный» экземпляр, потому что сбой этого экземпляра будет означать, что задача не будет выполнена, даже если доступны другие экземпляры. Таким образом, моя задача - обеспечить наличие экземпляра, доступного для выполнения. работа, тогда работа должна продолжаться.)

Для (2) я имел в виду наличие какого-то флага в базе данных, который экземпляры веб-приложения пытаются обновить, как только они получают уведомление SqlDependency в (1), по следующей строке (значительно упрощенной):

UPDATE StatusTable SET TaskStatus = 1 WHERE TaskStatus = 0

SELECT @@ROWCOUNT

Идея состоит в том, что только один экземпляр приложения мог бы обновить TaskStatus, и, таким образом, только один экземпляр имел бы @@ ROWCOUNT> 0. Тогда это был бы экземпляр, «выбранный» для передачи информации в Интернет. сервис.

Каковы недостатки этого подхода? Какие у меня есть другие варианты? (Примечание: отдельный сервис, выполняющий эту работу, не является опцией.)

1 Ответ

1 голос
/ 05 марта 2010

Глобальный «флаг» не будет работать, имейте в виду, что у вас есть несколько официантов и несколько уведомлений, вы не хотите, чтобы один «официант» принимал все уведомления , Чтобы надежно выбрать «ровно одну» задачу, используйте UPDATE с OUTPUT:

UPDATE TOP(1) StatusTable
   SET Status = 1
OUTPUT DELETED.TaskId
WHERE Status = 0;

Это рекомендуемый, надежный способ удаления строк из таблиц, используемых в качестве очередей, см. Параграф «Очереди» в Предложение OUTPUT .

Но теперь вы должны понимать, что 1) вы используете таблицы в качестве очередей 2) вы получаете уведомления из этих очередей и 3) вы используете Service Broker для доставки этих уведомлений (через SqlDependency, который внутренне использует Service Broker ). Так почему бы не использовать только простой Service Broker? Вам нужна очередь и служба , и каждый экземпляр запускает WAITFOR (RECEIVE ...) в этой очереди (то есть не опрос). Интересующая работа завершает свою работу с SEND к вашим услугам, уведомляя, что работа завершена. Ровно один из ваших экземпляров получит это уведомление и продолжит постобработку (т.е. доставит вызов веб-службы). Таким образом вы удаляете весь «поток» вокруг уведомлений (SqlDependency, глобальный флаг, таблицы, используемые в качестве очередей), и вы идете против простой инфраструктуры, которая в любом случае будет использоваться SqlDependency.

...