Метод Fire & Forget с использованием Task.Run не работает
Я прочитал много кодов, пытаясь использовать Task.Run
безуспешно.
Чего я хочу достичь:
- В событии ASP.NET WebForm (обработчик события click) вызовите метод Fire & Forget (не блокируйте текущий поток выполнения).
Что я пробовал и не понимаю, почему это не работает:
Первая версия:
protected void btn_Click(object sender, EventArgs e)
{
// Some actions
// Should insert a record in database --> OK
//Tried this call with and without ConfigureAwait(false)
Task.Run(() => MyClass.doWork()).ConfigureAwait(false);
// Should insert a record in database --> OK
// Some actions not blocked by the previous call
}
public static class MyClass
{
public static void doWork()
{
// Should insert a record in database --> NOT INSERTED
}
}
Вторая версия:
protected void btn_Click(object sender, EventArgs e)
{
// Some actions
// Should insert a record in database --> OK
Bridge.call_doWork();
// Should insert a record in database --> OK
// Some actions not blocked by the previous call
}
public static class Bridge
{
public static async Task call_doWork()
{
//Tried this call with and without ConfigureAwait(false)
await Task.Run(() => MyClass.doWork()).ConfigureAwait(false);
}
}
public static class MyClass
{
public static void doWork()
{
// Should insert a record in database --> NOT INSERTED
}
}
Поэтому я вызываю метод Fire & Forget, который должен вставить запись в базу данных, но запись не вставлена.
Вставки до и после вызова метода Fire & Forget завершены.
Я не знаю, как решить мою проблему.
2 ответа
HttpContext
не будет доступен в потоках, отличных от основного потока, поэтому вы не можете зависеть от него.
Но вы можете передавать данные из HttpContext
к вашему методу, когда вы запускаете задачу. Например:
Task.Run(() => MyClass.doWork(HttpContext.Current.Session["somedata"])).ConfigureAwait(false);
Почему я не получил событие EventViewer с вызовом HttpContext? Я получил один при использовании HostingEnvironment.QueueBackgroundWorkItem вместо Task.Run.
Хорошо, во-первых, если у вас есть QueueBackgroundWorkItem
доступно, почему бы вам использовать Task.Run
за огненную и забытую работу?
Как я опишу в своем блоге, используя Task.Run
для запуска и забывания на ASP.NET это действительно плохая идея! QueueBackgroundWorkItem
является минимальным жизнеспособным решением, и это только если вы принимаете ненадежность.
QueueBackgroundWorkItem
делает пару вещей для вас за Task.Run
: он регистрирует работу с помощью среды выполнения ASP.NET (которая минимизирует, но не исключает вероятность того, что работа не будет завершена), и он отслеживает исключения и регистрирует их для вас (именно поэтому вы видели уведомления о событиях).
Итак, вы видели событие для вашего исключения, потому что QBWI делал это для вас. Тогда как с Task.Run
код, исключение будет перехвачено и помещено в возвращаемый Task
(как и должно быть), и тогда ваш код полностью проигнорировал эту задачу, молча проглотив исключение.
Да! Я использую HttpContext, чтобы получить сессию. Но я не могу изменить это без изменения большого количества кода.
Как отметили другие, HttpContext
допустимо только в контексте запроса. Поэтому, когда вы явно запускаете фоновый код, он, конечно, не имеет контекста запроса. Фоновый код должен быть независимым от запросов по определению.
Но есть еще одно действительно важное соображение, которое, я думаю, вы упускаете из виду:
public static void doWork()
{
// Should insert a record in database --> NOT INSERTED
}
Вы уверены, что ваше приложение в порядке, если doWork
время от времени не выполняется? Потому что это то, что происходит с фоновыми задачами. ASP.NET был разработан, чтобы отвечать на запросы, а не запускать фоновые задачи.
Итак, каждый раз в голубой луне, запись, которая должна была быть вставлена doWork
не появится Если это неприемлемо, то не стоит заниматься огнем и забывать.