c# Telegram Bot выполнение длительной задачи
Здравствуйте у меня есть метод в телеграмм боте, который выполняет свои задачи длительное время, так как телеграмм не может получить ответ от бота, он шлёт новый запрос. Я сделал синхронный вызов, чтобы бот возвращал ответ серверу телеграмм, а сам продолжал свою задачу. Но по завершению работы в базу данных он не сохраняет данные. Вот пример кода
public async Task<IActionResult> BotStart([FromBody] Update update)
{
CultureInfo.CurrentCulture = CultureInfo.GetCultureInfo("en-US");
await SaveServiceModel();
TelegramBotClient client = new(BotConfig.Token);
if (update.Message != null && update.Message?.Text != null && update.Message.Type == Telegram.Bot.Types.Enums.MessageType.Text)
{
// UpdateMessage updateMessage = new(db, update, client, update.Message!.Chat.Id!);
//await updateMessage.Run();
if (update.Message.Text == "test")
Test(db, update, client);
}
if (update.CallbackQuery != null)
{
// UpdateCallbackQuery updateCallback = new(db, update, client, update.CallbackQuery.From.Id);
// await updateCallback.Run();
}
return Ok();
}
async Task Test(DataContext db, Update update, ITelegramBotClient client)
{
var user = db.User.FirstOrDefault(x => x.ID == update.Message.Chat.Id);
if (user.ReuseCode == true)
{
await client.SendTextMessageAsync(user.ID, "Обработка еще не завершена, дождитесь завершения");
return;
}
user.ReuseCode = true;
lock (this)
db.SaveChanges();
int wait = 120;
int delay = 1000;
int count = 0;
await client.SendTextMessageAsync(user.ID, "Обработка запущена");
while (count <= wait)
{
count++;
await Task.Delay(delay);
}
await client.SendTextMessageAsync(user.ID, "Обработка завершена");
user.ReuseCode = false;
lock (this)
db.SaveChanges(); // Не сохраняет user.ReuseCode = false; значение остаётся true
}
Ответы (1 шт):
async Task можно использовать только так
async Task MethodAsync()
{
// async операции
}
await MethodAsync();
либо
Task t = MethodASync();
и где-нибудь потом
await t;
Что касается неожидаемых методов типа "запустил и забыл", то в них нужно отдельно обрабатывать все исключения, в противном случае вы их не увидите, либо крашнете приложение без возможности перехватить исключение (поведение зависит от типа контекста синхронизации)
async void FireAndForget()
{
try
{
// async операции
}
catch (Exception ex)
{
Log(ex); // залогировать или вывести исключение
}
}
Некоторые разработчики делают логирующее расширение
public static class TaskExtensions
{
public static async void FireAndForget(this Task task)
{
try
{
await task;
}
catch (Exception ex)
{
Log(ex); // залогировать или вывести исключение
}
}
}
А потом вызывают вот так
MethodAsync().FireAndForget();
Cannot access a disposed context instance. A common cause of this error is disposing a context instance that was resolved from dependency injection and then later trying to use the same context instance elsewhere in your application. This may occur if you are calling 'Dispose' on the context instance, or wrapping it in a using statement. If you are using dependency injection, you should let the dependency injection container take care of disposing context instances. Object name: 'DataContext'.
DataContext нельзя использовать после того как выполнен возврат из контроллера. Найдите другой источник подключения к контексту БД, который будет жить столько сколько вам нужно.
