处理WebSocket错误
由于WebSocket是一个共享资源,错误处理与常规查询不同。在HTTP查询中,错误只有一个消费者。在WebSocket中,错误可能有多个消费者。
多个消费者的WebSocket错误
当您的网络断开或服务器关闭连接(因为它需要一个新令牌或其他原因),所有 订阅 都会被终止。您可以对它们逐个重试。下面的示例使用了一个非常简单的 指数退避 算法:
apolloClient.subscription(MySubscription()).toFlow().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": { }}
在这些情况下,流将抛出 SubscriptionOperationException
错误,您需要处理重试:
apolloClient.subscription(MySubscription()).toFlow().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}")}