diff --git a/Telegrator/Polling/ReactiveUpdateReceiver.cs b/Telegrator/Polling/ReactiveUpdateReceiver.cs index d6a0b72..082b281 100644 --- a/Telegrator/Polling/ReactiveUpdateReceiver.cs +++ b/Telegrator/Polling/ReactiveUpdateReceiver.cs @@ -1,4 +1,4 @@ -using Telegram.Bot; +using Telegram.Bot; using Telegram.Bot.Polling; using Telegram.Bot.Requests; using Telegram.Bot.Types; @@ -6,12 +6,12 @@ using Telegram.Bot.Types; namespace Telegrator.Polling { /// - /// Reactive implementation of for polling updates from Telegram. + /// Reactive update receiver for polling updates from Telegram. /// Provides custom update receiving logic with error handling and configuration options. /// /// The Telegram bot client for making API requests. /// Optional receiver options for configuring update polling behavior. - public class ReactiveUpdateReceiver(ITelegramBotClient client, ReceiverOptions? options) : IUpdateReceiver + public class ReactiveUpdateReceiver(ITelegramBotClient client, ReceiverOptions? options) { /// /// Gets the receiver options for configuring update polling behavior. @@ -63,7 +63,7 @@ namespace Telegrator.Polling try { request.Offset = update.Id + 1; - _ = updateHandler.HandleUpdateAsync(Client, update, cancellationToken); + await updateHandler.HandleUpdateAsync(Client, update, cancellationToken).ConfigureAwait(continueOnCapturedContext: false); } catch (Exception exception2) { diff --git a/Telegrator/Polling/UpdateHandlersPool.cs b/Telegrator/Polling/UpdateHandlersPool.cs index 5b3dd49..8b1cbb3 100644 --- a/Telegrator/Polling/UpdateHandlersPool.cs +++ b/Telegrator/Polling/UpdateHandlersPool.cs @@ -61,57 +61,72 @@ namespace Telegrator.Polling /// public async Task Enqueue(IEnumerable handlers) { - Result? lastResult = null; - foreach (DescribedHandlerInfo handlerInfo in handlers) + if (ExecutingHandlersSemaphore != null) { - if (lastResult?.NextType != null) - { - if (lastResult.NextType != handlerInfo.From.HandlerType) - continue; - } - - if (ExecutingHandlersSemaphore != null) - { - await ExecutingHandlersSemaphore.WaitAsync().ConfigureAwait(false); - } + await ExecutingHandlersSemaphore.WaitAsync().ConfigureAwait(false); + } + // Offload the entire processing of this update's handlers to a background task. + // This allows the Receiver to continue polling for NEW updates immediately, + // while this update acts as a self-contained unit of work. + _ = Task.Run(async () => + { try { - Alligator.LogDebug("Described handler '{0}' (Update {1})", handlerInfo.DisplayString, handlerInfo.HandlingUpdate.Id); - HandlerExecuting?.Invoke(handlerInfo); - - using (UpdateHandlerBase instance = handlerInfo.HandlerInstance) + Result? lastResult = null; + foreach (DescribedHandlerInfo handlerInfo in handlers) { - Task task = instance.Execute(handlerInfo); - HandlerEnqueued?.Invoke(handlerInfo); + if (lastResult?.NextType != null) + { + if (lastResult.NextType != handlerInfo.From.HandlerType) + continue; + } - await task.ConfigureAwait(false); - lastResult = task.Result; - ExecutingHandlersSemaphore?.Release(1); - } + try + { + Alligator.LogDebug("Described handler '{0}' (Update {1})", handlerInfo.DisplayString, + handlerInfo.HandlingUpdate.Id); + HandlerExecuting?.Invoke(handlerInfo); - if (lastResult.RouteNext) - { - Alligator.LogTrace("Handler '{0}' requested route continuation (Update {1})", handlerInfo.DisplayString, handlerInfo.HandlingUpdate.Id); + using (UpdateHandlerBase instance = handlerInfo.HandlerInstance) + { + Task task = instance.Execute(handlerInfo); + HandlerEnqueued?.Invoke(handlerInfo); + + await task.ConfigureAwait(false); + lastResult = task.Result; + } + + if (lastResult.RouteNext) + { + Alligator.LogTrace("Handler '{0}' requested route continuation (Update {1})", + handlerInfo.DisplayString, handlerInfo.HandlingUpdate.Id); + } + } + catch (NotImplementedException) + { + _ = 0xBAD + 0xC0DE; + } + catch (OperationCanceledException) + { + _ = 0xBAD + 0xC0DE; + break; + } + catch (Exception ex) + { + Alligator.LogError("Failed to process handler '{0}' (Update {1})", exception: ex, + handlerInfo.DisplayString, handlerInfo.HandlingUpdate.Id); + } + + if (lastResult != null && !lastResult.RouteNext) + break; } } - catch (NotImplementedException) + finally { - _ = 0xBAD + 0xC0DE; + ExecutingHandlersSemaphore?.Release(1); } - catch (OperationCanceledException) - { - _ = 0xBAD + 0xC0DE; - break; - } - catch (Exception ex) - { - Alligator.LogError("Failed to process handler '{0}' (Update {1})", exception: ex, handlerInfo.DisplayString, handlerInfo.HandlingUpdate.Id); - } - - if (lastResult != null && !lastResult.RouteNext) - break; - } + }, GlobalCancellationToken); } ///