2016-03-19 2 views
0

Я прочел себя синим, и я надеюсь, что есть простой ответ.Возврат из Контроллера, не дожидаясь завершения метода асинхронизации

У меня есть веб-API, который обрабатывает телеметрию из различных приложений «в дикой природе». В одном из моих контроллеров я хочу получить запрос на регистрацию ошибки в моей центральной базе мониторинга и как можно скорее ответить на ответ (У меня нет реального способа узнать, насколько критическая производительность может быть на конце звонящего, и уже есть значительный успех для создания первоначального запроса веб-службы).

По сути, то, что я ищу что-то вроде этого:

public IHttpActionResult Submit() { 
    try { 
     var model = MyModel.Parse(Request.Content.ReadAsStringAsync().Result); 

     // ok, I've got content, now log it but don't wait 
     // around to see the results of the logging, just return 
     // an Accepted result and begone 

     repository.SaveSubmission(model); // <-- fire and forget, don't wait 

     return Accepted(); 

    } catch (Exception) 
     return InternalServerError(); 
    } 
} 

Похоже, что это должно быть простым, но, по-видимому, нет. Я читал любое количество сообщений, указывающих все: от yup, просто используйте Task.Run() до Это ужасная ошибка, и вы никогда не сможете достичь того, чего хотите!

Проблема в моем сценарии, по-видимому, состоит в том, что этот процесс может быть завершен в середине процесса из-за его работы на рабочем процессе ASP.NET, независимо от того, какой тип разного способа вызова методов async (I ' вы проводите последние два часа или около того, читая различные вопросы SO и блоги Стивена Клири ... whew).

Если основной вопрос в этом случае заключается в том, что метод, который я бы «запустил и забыл», привязан к контексту http и подвержен раннему завершению рабочим процессом ASP.NET, тогда мой вопрос будет ...

Есть ли способ удалить этот метод/задачу/процесс из этого контекста ASP.NET? После того как этот запрос анализируется в модели, я сам не нуждаюсь в более конкретной необходимости работать в контексте http. Если есть простой способ, я могу вытащить его оттуда (и, таким образом, позволить запущенному веществу запустить перезапуск веб-сайта/пула приложений), это было бы здорово.

Ради должной осмотрительности, скажем, избавиться от хранилища контекста в контроллере и передать его в какой-то другой контекст:

public IHttpActionResult Submit() { 
    try { 
     var model = MyModel.Parse(Request.Content.ReadAsStringAsync().Result); 

     SomeStaticClass.SaveSubmission(model); // <-- fire and forget, don't wait 

     return Accepted(); 

    } catch (Exception) 
     return InternalServerError(); 
    } 
} 

... то единственное, что имеет значение «крест линии "- сама модель - никаких других зависимостей логики кода.

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

ответ

1

Хорошо, нашел еще несколько, которые были действительно полезны для моего сценария. Основной смысл этого, кажется, не делать этого.

Для этого необходимо отправить это отдельному компоненту в распределенной архитектуре (например, в очередь сообщений или служебных очередей, где их можно получить отдельно для обработки). Это единственный способ полностью выйти из рабочего процесса ASP.NET.

Один комментарий S/O (на другой пост S/O) приводит меня к двум статьям, которые я еще не видел перед публикацией: один Стивен Клири и еще один Фил Хаак.

SO сообщение интерес: How to queue background tasks in ASP.NET Web API

Огонь Стефана и забыть о ASP.NET блоге (отлично, жаль, что я нашел это первый): http://blog.stephencleary.com/2014/06/fire-and-forget-on-asp-net.html

И статья Фила: http://haacked.com/archive/2011/10/16/the-dangers-of-implementing-recurring-background-tasks-in-asp-net.aspx/

Следующий проект Стивена может представлять интерес, а также: https://github.com/StephenCleary/AspNetBackgroundTasks

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

(в данном конкретном случае отправка другой службы будет приближаться до тех пор, как запись в базу данных в любом случае, s o Я, скорее всего, откажусь от асинхронной обработки для этого метода api, но по крайней мере сейчас знаю, когда мне это действительно нужно)

1

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

Однако, если для вас важно время, чтобы ускорить время отклика, необходимо сделать запись базы данных как можно быстрее, используя некоторую форму кеша в памяти, чтобы медленная запись в хранилище физической базы данных была поставлена ​​в очередь фоновая задача. Сайты с большим объемом часто используют базы данных в памяти, которые реализуют такое поведение (я никогда не нуждался в нем, поэтому не могу помочь вам выбрать продукт), но вы также можете сами это кодировать, используя список объектов экземпляра для каждого приложения и фоновая петля некоторой формы.

Здесь применяются те статьи, которые вы связали, и это усложняется, поэтому предварительно построенная реализация почти всегда является наилучшим подходом - проверьте HangFire, если вы хотите создать заранее созданную реализацию «огонь-и-забыть».

+0

Спасибо за ответ. Я знаю, что запись db невелика, но вначале я подумал «почему бы нет», не понимая последствий. Я отказался от этой идеи. Я столкнулся с HangFire в своих путешествиях, исследуя это и, безусловно, помню, когда возникает настоящая необходимость. – jleach

Смежные вопросы