From 1079f38ed7969cc9b272eaeba1f9276c05361704 Mon Sep 17 00:00:00 2001 From: cryptooda Date: Wed, 5 Nov 2025 10:54:14 +0700 Subject: [PATCH] Add exception for webhook + add gracefull time before market decrease --- .../HealthChecks/CandleDataDetailedHealthCheck.cs | 1 + src/Managing.Application/Bots/TradingBotBase.cs | 8 ++++++++ src/Managing.Application/Shared/WebhookService.cs | 12 ++++++------ 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/Managing.Api/HealthChecks/CandleDataDetailedHealthCheck.cs b/src/Managing.Api/HealthChecks/CandleDataDetailedHealthCheck.cs index 56636cf7..9b509f1d 100644 --- a/src/Managing.Api/HealthChecks/CandleDataDetailedHealthCheck.cs +++ b/src/Managing.Api/HealthChecks/CandleDataDetailedHealthCheck.cs @@ -142,3 +142,4 @@ namespace Managing.Api.HealthChecks + diff --git a/src/Managing.Application/Bots/TradingBotBase.cs b/src/Managing.Application/Bots/TradingBotBase.cs index 073fe3fb..218bbaad 100644 --- a/src/Managing.Application/Bots/TradingBotBase.cs +++ b/src/Managing.Application/Bots/TradingBotBase.cs @@ -28,6 +28,7 @@ public class TradingBotBase : ITradingBot public readonly ILogger Logger; private readonly IServiceScopeFactory _scopeFactory; private const int NEW_POSITION_GRACE_SECONDS = 45; // grace window before evaluating missing orders + private const int CLOSE_POSITION_GRACE_MS = 20000; // grace window before closing position to allow broker processing (20 seconds) public TradingBotConfig Config { get; set; } public Account Account { get; set; } @@ -1324,6 +1325,13 @@ public class TradingBotBase : ITradingBot isForBacktest: Config.IsForBacktest); try { + // Grace period: give the broker time to process any ongoing close operations + // Using ConfigureAwait(false) to ensure non-blocking operation + if (!Config.IsForBacktest) + { + await Task.Delay(CLOSE_POSITION_GRACE_MS).ConfigureAwait(false); + } + Position closedPosition = null; await ServiceScopeHelpers.WithScopedServices( _scopeFactory, async (exchangeService, accountService, tradingService) => diff --git a/src/Managing.Application/Shared/WebhookService.cs b/src/Managing.Application/Shared/WebhookService.cs index 5d9dc0d5..dd8dd13c 100644 --- a/src/Managing.Application/Shared/WebhookService.cs +++ b/src/Managing.Application/Shared/WebhookService.cs @@ -22,11 +22,11 @@ public class WebhookService : IWebhookService _configuration = configuration; _logger = logger; _n8nWebhookUrl = _configuration["N8n:WebhookUrl"] ?? string.Empty; - + // Configure basic authentication if credentials are provided var username = _configuration["N8n:Username"]; var password = _configuration["N8n:Password"]; - + if (!string.IsNullOrEmpty(username) && !string.IsNullOrEmpty(password)) { var credentials = Convert.ToBase64String(Encoding.UTF8.GetBytes($"{username}:{password}")); @@ -63,12 +63,12 @@ public class WebhookService : IWebhookService } else { - _logger.LogWarning($"Failed to send webhook notification. Status: {response.StatusCode}"); + throw new Exception($"Failed to send webhook message. Status: {response.StatusCode}"); } } catch (Exception ex) { - _logger.LogError(ex, "Error sending webhook notification"); + SentrySdk.CaptureException(ex); } } @@ -100,12 +100,12 @@ public class WebhookService : IWebhookService } else { - _logger.LogWarning($"Failed to send webhook message. Status: {response.StatusCode}"); + throw new Exception($"Failed to send webhook message. Status: {response.StatusCode}"); } } catch (Exception ex) { - _logger.LogError(ex, "Error sending webhook message"); + SentrySdk.CaptureException(ex); } } } \ No newline at end of file