0

当网络错误导致重试时,我正在我的 React 应用程序中呈现通知。如果/重新建立连接(重试成功),我希望清除任何此类通知

当重试循环开始和超时时,我已经使用apollo-link-retry并使用了自定义attempts回调来改变缓存。这可行,但是当重试成功时通知会留在屏幕上,因为在成功重试时不会调用回调,所以我无法从缓存中清除通知。

我已经尝试使用apollo-link-error类似的问题来实现类似的逻辑。只有在发生错误并且成功重试不是错误时才会调用该链接。

这是我的apollo-link-retry“几乎”有效的配置:

const retryLink = new RetryLink({
  attempts: (count) => {
    let notifyType
    let shouldRetry = true
    if (count === 1) {
      notifyType = 'CONNECTION_RETRY'
      shouldRetry = true
    } else if (count <= 30) {
      shouldRetry = true
    } else {
      notifyType = 'CONNECTION_TIMEOUT'
      shouldRetry = false
    }
    if (notifyType) {
      client.mutate({
        mutation: gql`
          mutation m($notification: Notification!) {
            raiseNotification(notification: $notification) @client
          }
        `,
        variables: {
          notification: { type: notifyType }
        }
      })
    }
    return shouldRetry
  }
})

也许我需要实现一个自定义链接来完成这个?我希望找到一种方法来利用良好的重试逻辑,apollo-link-retry并随着逻辑的进展另外发出一些状态来缓存。

4

1 回答 1

0

我通过做两件事实现了预期的行为:

attempts通过函数维护链接上下文中的重试计数:

new RetryLink({
  delay: {
    initial: INITIAL_RETRY_DELAY,
    max: MAX_RETRY_DELAY,
    jitter: true
  },
  attempts: (count, operation, error) => {
    if (!error.message || error.message !== 'Failed to fetch') {
      // If error is not related to connection, do not retry
      return false
    }
    operation.setContext(context => ({ ...context, retryCount: count }))
    return (count <= MAX_RETRY_COUNT)
  }
})

实现自定义链接,该链接在链接链的下方订阅错误和已完成事件,并使用新的上下文字段来决定是否应发出通知:

new ApolloLink((operation, forward) => {
  const context = operation.getContext()
  return new Observable(observer => {
    let subscription, hasApplicationError
    try {
      subscription = forward(operation).subscribe({
        next: result => {
          if (result.errors) {
            // Encountered application error (not network related)
            hasApplicationError = true
            notifications.raiseNotification(apolloClient, 'UNEXPECTED_ERROR')
          }
          observer.next(result)
        },
        error: networkError => {
          // Encountered network error
          if (context.retryCount === 1) {
            // Started retrying
            notifications.raiseNotification(apolloClient, 'CONNECTION_RETRY')
          }
          if (context.retryCount === MAX_RETRY_COUNT) {
            // Timed out after retrying
            notifications.raiseNotification(apolloClient, 'CONNECTION_TIMEOUT')
          }
          observer.error(networkError)
        },
        complete: () => {
          if (!hasApplicationError) {
            // Completed successfully after retrying
            notifications.clearNotification(apolloClient)
          }
          observer.complete.bind(observer)()
        },
      })
    } catch (e) {
      observer.error(e)
    }
    return () => {
      if (subscription) subscription.unsubscribe()
    }
  })
})
于 2019-08-30T08:51:37.753 回答