Подтвердить что ты не робот

В asp.net-mvc, как я могу запустить дорогостоящую операцию без замедления работы пользователя?

У меня есть сайт asp.net-mvc, и я использую nhibernate для своего ORM.

У меня есть текущее действие контроллера, которое выполняет базовое обновление CRUD (запрашивает элемент из базы данных, а затем обновляет кучу значений и возвращает обратно в таблицу db). Затем он возвращает простой ответ json клиенту для указания успеха или ошибки.

 public ActionResult UpdateEntity(MyEntity newEntity)
 {
      var existingEntity = GetFromRepository(newEntity.Id);
      UpdateExistingEntity(newEntity, existingEntity);
      return Json(SuccessMessage);
 }

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

 public ActionResult UpdateEntity(MyEntity newEntity)
 {
      var existingEntity = GetFromRepository(newEntity.Id);
      bool keyFieldsHaveChanged = UpdateExistingEntity(newEntity, existingEntity);
      if (keyFieldsHaveChanged)
     {
          GenerateEmails();
          GenerateReports();
     }
    return Json(SuccessMessage);
 }

что он будет слишком медленным для пользователей, которые могут кого-то обновить. Есть ли в любом случае (asyngc?), Чтобы получить дорогостоящую операцию, вызванную действием контроллера, но не из-за этого замедлить действие контроллера?

4b9b3361

Ответ 1

Я сделал это раньше.

Самый надежный способ - использовать Asynchronous Controller или, еще лучше, независимую службу, такую ​​как служба WCF.

Но, по моему опыту, мне просто нужно было сделать "простую" задачу с одним слоем, такую ​​как аудит или отчетность, как вы говорите.

В этом примере простой способ - отключить Task:

public ActionResult Do()
{
    SomethingImportantThatNeedsToBeSynchronous();

    Task.Factory.StartNew(() => 
    {
       AuditThatTheUserShouldntCareOrWaitFor();
       SomeOtherOperationTheUserDoesntCareAbout();
    });

    return View();

}

Это простой пример. Вы можете запускать столько задач, сколько хотите, синхронизировать их, получать уведомления, когда они заканчиваются, и т.д.

В настоящее время я использовал выше, чтобы загружать Amazon S3.

Ответ 2

Если намерение немедленно вернуть JSON и оставить интенсивную работу для асинхронного запуска в фоновом режиме, не затрагивая работу пользователя, вам необходимо запустить новый фоновый поток. AsyncController вам не поможет.

Есть много аргументов в том, что он голодает пул запросов потока, делая это (это правда), но аргумент счетчика - вы должны голодать пулом, потому что сервер занят работой. Конечно, в идеале вы должны перенести работу на другой сервер полностью через очереди/распределенные системы и т.д., Но это сложное решение. Если вам не нужно обрабатывать сотни запросов, вам не нужно учитывать этот вариант, так как вряд ли это когда-либо вызовет проблему. Это зависит от требований к масштабируемости вашего решения, от того, как долго будет проходить фоновый процесс и как часто он называется. Самое простое решение заключается в следующем:

public ActionResult UpdateEntity(MyEntity newEntity)
{
    var existingEntity = GetFromRepository(newEntity.Id);
    bool keyFieldsHaveChanged = UpdateExistingEntity(newEntity, existingEntity);
    if (keyFieldsHaveChanged)
    {
        ThreadPool.QueueUserWorkItem(o =>
                                        {
                                            GenerateEmails();
                                            GenerateReports();
                                        });

    }
    return Json(SuccessMessage);
}

Ответ 3

Вам следует выполнять асинхронные операции и асинхронные контроллеры, чтобы не блокировать пул потоков, а не страдать от других пользователей веб-сайта. Когда задача выполняется долго, поток, взятый из пула потоков asp.net, зарезервирован и не возвращается в пул до завершения операции. Если будет много одновременных длительных задач, многие потоки будут зарезервированы ими, поэтому есть вероятность, что другие пользователи, которые посещают ваш сайт, пострадают от ожидания. Операции ASYNC НЕ СОЗДАЮТ ЛЮБЫЕ ФАКТОРЫ КОДА. Я советую вам использовать асинхронные контроллеры только для случая, о котором я писал выше, но этого недостаточно. Я думаю, вы должны использовать некоторые ссылки или ajax для запуска операции на сервере и позволить пользователю продолжить его серфинг на сайте. Как только операция завершена, при обновлении следующей страницы пользователь должен быть уведомлен о завершении выполнения задачи. И еще одно доказательство того, что бизнес-коды не должны записываться в контроллер. Для этого вам нужно разделить службы.

Ответ 4

Я думаю, что вы действительно хотите, чтобы роль рабочего была похожа на Windows Azure.

http://www.microsoft.com/windowsazure/features/compute/

Я не уверен, как наилучшим образом реализовать это в чистом MVC без очереди Azure. И, в зависимости от того, где вы размещаете (интернет-хостер, собственный сервер с корнем и т.д.), Есть сложности.

Ответ 5

Это старый вопрос, поэтому я считаю, что он нуждается в обновлении.

Я рекомендую использовать HangFire (http://hangfire.io). При этом вы можете просто выполнить свою работу даже в веб-приложении. HangFire будет следить за тем, чтобы работа выполнялась хотя бы один раз.

// Static methods are for demo purposes
BackgroundJob.Enqueue(
    () => Console.WriteLine("Simple!"));

Вы также можете просмотреть статус всех заданий в очереди в хорошем пользовательском интерфейсе.

Ответ 6

Взяв идею @IKEA Riot из службы Windows и флага базы данных, вы можете использовать что-то вроде Quartz.Net или компонент Castle.Scheduler, который интегрируется в ваш веб-сайт или превращается в отдельную службу Windows, которая может запускать определенные задания.

fooobar.com/questions/77907/...

Ответ 7

Это не в основном асинхронно, так как я правильно прочитал ваш вопрос. Это длительная работа. Вы должны разгрузить длительную операцию в фоновые задания. Приложения ASP.NET не подходят для выполнения фоновых заданий. Я вижу несколько вариантов, с которыми вы можете пойти:

  • Служба Windows - это может опросить вашу БД для определенного состояния и может инициировать действие из этого состояния.
  • Служба WCF - приложение ASP.NET может отправлять асинхронный запрос в службу WCF, не дожидаясь ответа
  • Там могут быть другие, такие как BizTalk, но это зависит от того, как ваше приложение структурировано и т.д.

В пользовательском интерфейсе вы можете опросить таймер, чтобы предоставить статус пользователю (если вы думаете, что пользователь должен знать этот статус немедленно) или отправить электронное письмо пользователю, когда действие будет завершено.

На стороне примечания важно выполнить ваш ввод-вывод с помощью asyn-операций, а другие уже предоставили некоторые хорошие ссылки о том, как вы можете это сделать.

Ответ 8

ЕСЛИ вы думаете об опыте пользователя (пользователь не должен ждать, пока выполняются эти задачи) и надежности (задачи должны быть установлены в очередь и выполняться, даже если приложение повторно используется), вы можете использовать MSMQ.

MSMQ предоставляет рубестовое решение для операций assync. Он поддерживает операции синхронизации, предоставляет журналы и управляемый API, и в качестве основного фокуса исключает такую ​​ситуацию.

Взгляните на эти статьи:

Введение в MSMQ

Программирование MSMQ в .Net

Ответ 9

Используйте служебную шину для публикации сообщения, когда объект обновляется. Таким образом, вы не только избежите длительных операций в контроллерах, но и сможете отделить контроллеры от действий, которые необходимо выполнить, когда что-то произойдет.

Вы также можете использовать События домена для обработки действий и объединить их с вашим любимым контейнером ioc: Advanced StructureMap: подключение реализаций для открытия общих типов