使用Coroutines批量调用API出现HTTP 503错误的解决方案咨询
解决API并发调用HTTP 503问题的方案
你的问题核心是瞬间发起30个API请求触发了服务端限流机制(HTTP 503通常表示服务因请求过载暂时不可用)。直接加固定延迟会严重影响用户体验,以下是更高效的解决方法:
1. 用信号量(Semaphore)控制并发数
通过kotlinx.coroutines.sync.Semaphore限制同时发起的API请求数量,比如同时允许4-5个请求,既保证执行效率,又不会触发服务端限流。
修改后的代码示例:
override suspend fun getScoreboard(docId: String): ScoreboardResult { val scoreboardResult = ScoreboardResult() try { withContext(Dispatchers.IO) { val cfHandles = getCfHandles(docId = docId) val contests = getContests(docId = docId).split(";") Log.d(TAG, "contests size = ${contests.size} ===> $contests") Log.d(TAG, Thread.currentThread().toString()) // 限制同时最多5个并发请求,可根据API实际限流调整 val semaphore = Semaphore(5) val jobs = mutableListOf<Job>() // 保证结果更新线程安全 val mutex = Mutex() for(contest in contests) { val options = hashMapOf("contestId" to contest, "handles" to cfHandles) Log.d(TAG, "Doing contest: $contest") val job = launch { semaphore.acquire() // 获取请求许可,无许可则等待 try { Log.d(TAG, Thread.currentThread().toString()) val contestScore = getPartiesScore(options = options) if (contestScore.status == Constants.CF_API_SUCCESS_STATUS) { Log.d(TAG, "Success $contest") mutex.withLock { scoreboardResult.updateScore(contestScore.result.rows) } } else { throw CustomException(message = "Failed at contest: $contest") } } finally { semaphore.release() // 释放许可,让后续请求可以执行 } } jobs.add(job) } jobs.joinAll() // 等待所有请求完成后再返回结果 } Log.d(TAG, "Everything went well") return scoreboardResult } catch (exception: Exception) { Log.d(TAG, "Something bad happened : ${exception.message}") scoreboardResult.exception = exception return scoreboardResult } }
2. 增加指数退避重试机制
针对偶尔出现的503错误,添加自动重试逻辑,用指数递增的延迟(比如100ms→200ms→400ms),既避免频繁重试触发限流,又能提高请求成功率。
封装重试函数示例:
private suspend fun fetchContestScore(options: HashMap<String, String>): PartiesScore { var currentDelay = 100L val maxRetries = 3 repeat(maxRetries) { attempt -> try { return getPartiesScore(options) } catch (e: Exception) { if (attempt == maxRetries - 1) throw e // 最后一次重试失败则抛出异常 delay(currentDelay) currentDelay *= 2 // 延迟翻倍 } } throw IllegalStateException("Retry logic failed") }
方案优势
- 信号量控制并发:避免瞬间请求过载,让请求均匀分散,适配服务端的速率限制
- 指数退避重试:处理临时服务过载情况,比固定延迟更高效,不会拉长整体耗时
- 线程安全修复:原代码中
lateinit var contestScore存在多协程数据冲突风险,修改后用局部变量+Mutex保证结果更新安全
内容的提问来源于stack exchange,提问作者kotlin_noob
相关产品推荐
相关产品推荐

