处理 WebSocket 错误
由于 WebSocket 是共享资源,错误处理与常规查询不同。在 HTTP 查询中,错误只有一个消费者。WebSockets 中,一个错误可能有多个消费者。
ⓘ 注意
从 4.0.0 版本开始,Apollo Kotlin提供了一个新的实验性 WebSocket 实现,该实现提供更好的默认设置、更好的重试和错误处理 API。目标是将来取代当前实现。
如果您有兴趣尝试,请参阅实验性 WebSocket 页面。
有多个消费者的 WebSocket 错误
当您的网络出现问题或您的服务器关闭连接(因为它想要新的令牌或其他原因时),所有 订阅 都将终止。您可以单独重试它们。下面的例子使用一个非常简单 指数退避 算法:
apolloClient.subscription(MySubscription()).toFlow().onEach {// Throw the exception so we can use retryWhenit.exception?.let { throw it }}.retryWhen { e, attempt ->delay(2.0.pow(attempt.toDouble()).toLong())// retry after the delaytrue}.collect {println("trips booked: ${it.data?.tripsBooked}")}
这有几个缺点(不包括简单的指数退避实现)
- 此代码必须在不同的地方实现
- 尝试与收集器生命周期相关联,如果网络恢复正常,则无法重置它
相反,您可以在配置 ApolloClient 时在一个更集中的位置管理它
val apolloClient = ApolloClient.Builder().httpServerUrl("https://127.0.0.1:8080/graphql").webSocketServerUrl("https://127.0.0.1:8080/subscriptions").webSocketReopenWhen { e, attempt ->delay(2.0.pow(attempt.toDouble()).toLong())// retry after the delaytrue}
上面的代码将记住所有当前的 订阅,并自动重新订阅服务器,而无需在每个屏幕上调用 retry
。
具有单个消费者的 WebSocket 错误
在某些情况下,您可能遇到仅针对单一消费者的错误。这种情况通常发生在 错误消息:
{"id": "3f32558f-49a3-4dc2-9d1c-445adf0a66c7","type": "error","payload": { }}
在这些情况下,Flow 将在其 exception
抛出 SubscriptionOperationException
并终止 ApolloResponse
。您可以按如下方式处理重试:
apolloClient.subscription(MySubscription()).toFlow().onEach {// Throw the exception so we can use retryWhenit.exception?.let { throw it }}.retryWhen { e, attempt ->if (e is SubscriptionOperationException) {// handle the operation error} else {// handle global errors that were not caught by webSocketReopenWhen}}.collect {println("trips booked: ${it.data?.tripsBooked}")}