Kotlin Channel的trySend返回Failed时如何实现带退避的自动重试
问题根因
你遇到的冷启动首次trySend失败且isClosed = false的核心原因是actor默认使用Rendezvous Channel(会合通道),该通道无内置缓冲区,必须等接收端(即actor代码块内的consumeEach逻辑)启动就绪后,发送才能成功。冷启动阶段协程调度存在时序差,首次调用trySend时actor的接收逻辑还未完成初始化,就会触发未关闭状态下的发送失败。
解决方案
分为两种实现路径,优先选择根源规避方案。
方案1:修改actor配置从根源规避(最优)
直接给actor指定非零缓冲区容量,不需要额外写重试逻辑,冷启动时序问题直接解决:
// 初始化时指定缓冲区容量为无限,也可以根据业务需求设置有限值比如16 private val actor = scope.actor<Action>(capacity = Channel.UNLIMITED) { channel.consumeEach { action -> _reactions.tryEmit(reduce(action = action)) } }
修改后原有send方法不需要任何改动,trySend只要channel未关闭就会返回成功。
方案2:自定义带指数退避的重试逻辑
如果不能修改actor的原有配置,可以自行实现重试逻辑:
2.1 挂起式重试实现(推荐,资源占用更低)
// 重试配置,可根据业务调整 private const val MAX_RETRY_TIMES = 3 private const val INITIAL_BACKOFF_MS = 50L suspend fun sendWithRetry(action: Action) { var retryCount = 0 var backoffMs = INITIAL_BACKOFF_MS var sendResult: ChannelResult<Unit> do { sendResult = actor.trySend(action) if (sendResult.isSuccess) return // channel已关闭时直接终止重试 if (sendResult.isClosed) { // 可在此处添加channel关闭的异常处理逻辑 return } retryCount++ if (retryCount > MAX_RETRY_TIMES) { // 重试耗尽的兜底逻辑,比如埋点上报、本地缓存动作 return } delay(backoffMs) backoffMs *= 2 // 指数退避,每次等待时长翻倍 } while (retryCount <= MAX_RETRY_TIMES) } // 如果需要在非挂起函数中调用,用业务scope包裹即可 fun send(action: Action) { scope.launch { sendWithRetry(action) } }
2.2 非协程实现(不推荐,会阻塞线程)
如果不允许使用协程实现,可以用线程sleep实现退避,禁止在主线程调用:
private const val MAX_RETRY_TIMES = 3 private const val INITIAL_BACKOFF_MS = 50L fun send(action: Action) { var retryCount = 0 var backoffMs = INITIAL_BACKOFF_MS var sendResult: ChannelResult<Unit> do { sendResult = actor.trySend(action) if (sendResult.isSuccess) return if (sendResult.isClosed) return retryCount++ if (retryCount > MAX_RETRY_TIMES) return try { Thread.sleep(backoffMs) } catch (e: InterruptedException) { Thread.currentThread().interrupt() return } backoffMs *= 2 } while (retryCount <= MAX_RETRY_TIMES) }
注意事项
- 优先选择方案1修改actor缓冲区配置,代码侵入性最低,也不会引入重试带来的额外复杂度
- 重试逻辑必须设置最大重试次数,避免出现无限重试导致的资源泄漏
- 如果业务场景不允许丢失动作,重试耗尽后可以将动作存入本地持久化存储,等后续合适时机重新发送
内容的提问来源于stack exchange,提问作者Hector
相关产品推荐
相关产品推荐

