fix(network): retry transient connection/IO failures to api.meshtastic.org (#5870)

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
James Rich
2026-06-19 13:23:37 -05:00
committed by GitHub
parent 3fe1deb01c
commit a5f9238183
3 changed files with 21 additions and 10 deletions

View File

@@ -48,6 +48,7 @@ import org.koin.core.annotation.Single
import org.meshtastic.core.common.BuildConfigProvider
import org.meshtastic.core.network.HttpClientDefaults
import org.meshtastic.core.network.KermitHttpLogger
import org.meshtastic.core.network.configureDefaultRetry
private const val DISK_CACHE_PERCENT = 0.02
private const val MEMORY_CACHE_PERCENT = 0.25
@@ -104,10 +105,7 @@ class NetworkModule {
connectTimeoutMillis = HttpClientDefaults.TIMEOUT_MS
socketTimeoutMillis = HttpClientDefaults.TIMEOUT_MS
}
install(plugin = HttpRequestRetry) {
retryOnServerErrors(maxRetries = HttpClientDefaults.MAX_RETRIES)
exponentialDelay()
}
install(plugin = HttpRequestRetry) { configureDefaultRetry() }
if (buildConfigProvider.isDebug) {
install(plugin = Logging) {
logger = KermitHttpLogger

View File

@@ -16,8 +16,10 @@
*/
package org.meshtastic.core.network
import io.ktor.client.plugins.HttpRequestRetryConfig
/**
* Shared HTTP client configuration constants used by both Android and Desktop Ktor `HttpClient` setups.
* Shared HTTP client configuration used by both Android and Desktop Ktor `HttpClient` setups.
*
* These values are consumed by the platform-specific Koin modules (`NetworkModule` on Android, `DesktopKoinModule` on
* Desktop) when installing [io.ktor.client.plugins.HttpTimeout] and [io.ktor.client.plugins.HttpRequestRetry].
@@ -26,9 +28,22 @@ object HttpClientDefaults {
/** Timeout in milliseconds for connect, request, and socket operations. */
const val TIMEOUT_MS = 30_000L
/** Maximum number of automatic retries on server errors (5xx). */
/** Maximum number of automatic retries on server errors (5xx) and transient connection/IO failures. */
const val MAX_RETRIES = 3
/** Base URL for the Meshtastic public API. Installed via the `DefaultRequest` plugin. */
const val API_BASE_URL = "https://api.meshtastic.org/"
}
/**
* Shared [io.ktor.client.plugins.HttpRequestRetry] policy for both engines.
*
* Retries on 5xx server errors and on transient connection/IO failures (dropped sockets, DNS blips, read timeouts) —
* the common failure mode on flaky cellular — with exponential backoff. [HttpClientDefaults.MAX_RETRIES] applies to
* both rules.
*/
fun HttpRequestRetryConfig.configureDefaultRetry() {
retryOnServerErrors(maxRetries = HttpClientDefaults.MAX_RETRIES)
retryOnException(maxRetries = HttpClientDefaults.MAX_RETRIES, retryOnTimeout = true)
exponentialDelay()
}

View File

@@ -44,6 +44,7 @@ import org.meshtastic.core.model.NetworkDeviceLink
import org.meshtastic.core.model.NetworkFirmwareReleases
import org.meshtastic.core.network.HttpClientDefaults
import org.meshtastic.core.network.KermitHttpLogger
import org.meshtastic.core.network.configureDefaultRetry
import org.meshtastic.core.network.repository.MQTTRepository
import org.meshtastic.core.network.service.ApiService
import org.meshtastic.core.network.service.ApiServiceImpl
@@ -245,10 +246,7 @@ private fun desktopPlatformStubsModule() = module {
connectTimeoutMillis = HttpClientDefaults.TIMEOUT_MS
socketTimeoutMillis = HttpClientDefaults.TIMEOUT_MS
}
install(HttpRequestRetry) {
retryOnServerErrors(maxRetries = HttpClientDefaults.MAX_RETRIES)
exponentialDelay()
}
install(HttpRequestRetry) { configureDefaultRetry() }
if (DesktopBuildConfig.IS_DEBUG) {
install(Logging) {
logger = KermitHttpLogger