453bcdaba9ef
fix: dialer takes 60s cooldown after clean-complete close (v2.9.17)
- time
- 2026-07-31 11:01 UTC · 2 months ago
- machine
- koh2
- parent
- 36feed1efeba
↓ peach-android-453bcdab.tar.gzatlas at this save
files changed3 files
VERSION+1 −1app/src/main/java/com/peachpasswords/sync/CloudRelayReconnectListener.kt+9 −0app/src/test/java/com/peachpasswords/sync/CloudRelayReconnectListenerTest.kt+9 −2VERSION+1 −1
@@ -1 +1 @@1-2.9.16\ No newline at end of file1+2.9.17\ No newline at end of fileapp/src/main/java/com/peachpasswords/sync/CloudRelayReconnectListener.kt+9 −0
@@ -53,6 +53,14 @@5353 internal const val DIAL_SESSION_TIMEOUT_MS = SESSION_TIMEOUT_MS + DIAL_HANDSHAKE_HEADROOM_MS5454 /** Slower than the waiter's retry, so the peer is already in the room. */5555 private const val DIAL_RETRY_DELAY_MS = 5_000L56+/**57+ * Cooldown the dialer takes after a clean `relay session complete` close58+ * before re-dialing the same target. Must clear the reconcile cadence by59+ * an order of magnitude or the dialer re-dials into a closed socket and60+ * burns a full 20s ping/pong timeout per cycle. 60s is conservative: the61+ * reconcile loop will re-spawn this target sooner if anything changes.62+ */63+private const val DIAL_CLEAN_COMPLETE_COOLDOWN_MS = 60_000L5664 private const val RELAY_CONNECT_TIMEOUT_MS = 10_000L5765 private const val RELAY_INBOX_CAPACITY = 85866 private const val PEACH_SYNC_LOG_TAG = "PeachSync"@@ -122,6 +130,7 @@122130 }123131 124132 internal fun nextRelayRetryDelay(current: Long, succeeded: Boolean, dialer: Boolean): Long {133+ if (succeeded && dialer) return DIAL_CLEAN_COMPLETE_COOLDOWN_MS125134 val initial = if (dialer) DIAL_RETRY_DELAY_MS else RETRY_DELAY_MS126135 return if (succeeded) initial else (current * 2).coerceAtMost(MAX_RETRY_DELAY_MS)127136 }app/src/test/java/com/peachpasswords/sync/CloudRelayReconnectListenerTest.kt+9 −2
@@ -70,11 +70,18 @@7070 }7171 7272 @Test73- fun `relay retry backs off after failures and resets after success`() {73+ fun `relay retry backs off after failures, resets on waiter success, and cooldowns on dialer success`() {74+ // Failures double up to the cap regardless of role.7475 assertEquals(2_000L, nextRelayRetryDelay(1_000L, succeeded = false, dialer = false))7576 assertEquals(30_000L, nextRelayRetryDelay(20_000L, succeeded = false, dialer = false))77+ // A waiter that just finished a clean session is parked for the78+ // ordinary RETRY_DELAY_MS; nothing for it to reconcile against.7679 assertEquals(1_000L, nextRelayRetryDelay(30_000L, succeeded = true, dialer = false))77- assertEquals(5_000L, nextRelayRetryDelay(30_000L, succeeded = true, dialer = true))80+ // A dialer that just finished a clean session must NOT re-dial at the81+ // reconcile cadence — that is the idle-burn. It takes the long cooldown82+ // so the reconcile loop has time to either re-spawn it for a reason or83+ // leave it parked.84+ assertEquals(60_000L, nextRelayRetryDelay(30_000L, succeeded = true, dialer = true))7885 }7986 8087 @Test