From c01ef7a059467cf67219b1f14923996f8da8c043 Mon Sep 17 00:00:00 2001 From: Janez T Date: Tue, 17 Mar 2026 10:48:53 +0100 Subject: [PATCH] =?UTF-8?q?fix:=20DM=20retry=20stuck=20=E2=80=94=20reduce?= =?UTF-8?q?=20jitter,=20fix=20flood-only=20retry=20count?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - maxRetryAttemptsFloodOnly: 1→0 (was causing an extra retry for flood contacts that the official app doesn't do) - isLastAttempt: fix off-by-one (retryAttempt already incremented when called from _scheduleRetry) - Reduce ACK timeout jitter from 1-8s to 0.5-2s to avoid long waits that make the UI appear stuck --- lib/providers/helpers/message_retry_manager.dart | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/lib/providers/helpers/message_retry_manager.dart b/lib/providers/helpers/message_retry_manager.dart index 9f36cc6..8a171f0 100644 --- a/lib/providers/helpers/message_retry_manager.dart +++ b/lib/providers/helpers/message_retry_manager.dart @@ -25,7 +25,8 @@ class MessageRetryManager { static const int maxRetryAttemptsWithPath = 5; /// No retries for flood-only contacts (no known path). - static const int maxRetryAttemptsFloodOnly = 1; + /// Value 0 means: don't retry at all, go straight to fallback/fail. + static const int maxRetryAttemptsFloodOnly = 0; @Deprecated('Use maxRetryAttemptsForContact instead') static const int maxRetryAttempts = maxRetryAttemptsWithPath; @@ -75,8 +76,8 @@ class MessageRetryManager { } } - // Add random jitter: 1000-8000ms (matches official app) - final jitterMs = 1000 + _rng.nextInt(7001); + // Add random jitter: 500-2000ms to avoid collision + final jitterMs = 500 + _rng.nextInt(1501); return baseTimeout + jitterMs; } @@ -90,11 +91,14 @@ class MessageRetryManager { return message.retryAttempt < maxRetryAttemptsForContact(contact); } - /// Whether the next attempt is the last one. + /// Whether this is the last retry attempt. /// When true, the caller should reset the path to force flood mode. + /// + /// Note: called AFTER retryAttempt has been incremented, so we compare + /// directly against maxAttempts (not +1). bool isLastAttempt(Message message, Contact contact) { final maxAttempts = maxRetryAttemptsForContact(contact); - return maxAttempts > 1 && message.retryAttempt + 1 >= maxAttempts; + return maxAttempts > 1 && message.retryAttempt >= maxAttempts; } /// Track a retry attempt for a message