kamilkisiela / apollo-angular

A fully-featured, production ready caching GraphQL client for Angular and every GraphQL server 🎁
https://apollo-angular.com
MIT License
1.5k stars 312 forks source link

Cannot recover from errors via refetch #1553

Open nanitohb opened 4 years ago

nanitohb commented 4 years ago

Describe the bug

I am using watchQuery and refetch to update the UI, but if the watchQuery or one refetch fail with an error i can catch the error and the UI refresh the error but the next querys (refetch) dont trigger the maps, subscriptions or catchError and does not refresh the UI (even used async pipe and select pipe).

The request is send to server and the response its ok, but after one error its stops refreshing UI.

I read on apollographql/react-apollo github "Cannot recover from errors via refetch or resetStore #2070" this:

"So what happens is: a) first query returns, error. Picked up by RA, renders. b) refetch happens (either directly or via resetStore). Due to (a) being an error and 2. above, RA is never informed. c) refetch query returns. In 1. above, RA compares it to the first query, which has networkStatus === 7, so it throws it away."

To Reproduce Steps to reproduce the behavior: 1) Make a request with wathQuery 2) Turn off your server. 3) Make a refetch (it will trigger the error catch). 4) Turno on your server. 5) Make another refetch (it will make the request but it will not refresh the UI, neither trigger mappings nor errors catch).

Expected behavior

When the second refetch triggers must refresh UI and trigger maps or catchErrros.

Environment:

with this other context i worked this same problem too

In fact i updated because i was hoping it was resolved.

Additional context

I workaround this by implementing interceptor, with the interceptor I catch every error and return a emtpy HTTP response (return of(new HttpResponse({body: []}));) with this it will always map because it thinks that is always correct and not an error, but when there is an error the data atribute of response in the mapping o subscribe will be undefined (response.data == undefined), meaning an error, if you want you can agregate to the response body an error atribute or the error like it was data.

nanitohb commented 4 years ago

Talking about the workaround, we need to know that it will trigger the error the first time in my case beacuse i am sending and undefined data, if it fail again (consecutively) it will not map, because we are mapping or subscribing to the valueChanges obsevable and the value did not change (it will be empty), but when the server turn on again it will trigger because it will diferent (not undefined) if you need to trigger, even if it fail again, you can return a new Date value each time theres and error like it was data, and force a value change (i will do this because and need for a loading view to disapear each time).

mhamern commented 2 years ago

Facing the same issue, is there any progress on fixing that?

waeljammal commented 1 year ago

I'm having the same issue, trying to handle errors and recover when using refetch and query valueChanges stops working entirely after an error

toriphes commented 1 year ago

Hello, I'm facing the same issue. I made an example on stackblitz to reproduce the problem:

https://stackblitz.com/edit/angular-ivy-6yr6hs?file=src/app/app.component.ts

When a network error occurs the apollo-angular observable wrapper get into an error state and close the data stream. Using the catchError operator there is no way to prevent this from happening and the valueChanges observable is no longer usable.

Refetching data after the error, continue to execute graphql queries on the network but the observable no longer emits new values.

I don't know if this behavior is intentional but it makes it difficult to handle this type of errors.

markharding commented 1 year ago

Also running into this issue, after a server error no more events are emitted.


ApolloError: Http failure response for http://localhost:8080/api/graphql: 500 Internal Server Error
    at new ApolloError (index.js:26:28)
    at QueryManager.js:665:19
    at both (asyncMap.js:16:53)
    at asyncMap.js:9:72
    at new ZoneAwarePromise (zone.js:1429:21)
    at Object.then (asyncMap.js:9:24)
    at Object.error (asyncMap.js:17:49)
    at notifySubscription (module.js:137:18)
    at onNotify (module.js:176:3)
    at SubscriptionObserver.error (module.js:229:5)
    at iteration.js:4:68
    at Array.forEach (<anonymous>)
    at iterateObserversSafely (iteration.js:4:25)
    at Object.error (Concast.js:37:43)
    at notifySubscription (module.js:137:18)
    at onNotify (module.js:176:3)
    at SubscriptionObserver.error (module.js:229:5)
    at Object.error (ngApolloLinkHttp.mjs:172:42)
    at ConsumerObserver.error (Subscriber.js:102:33)
    at SafeSubscriber._error (Subscriber.js:64:30)
    at SafeSubscriber.error (Subscriber.js:40:18)
    at OperatorSubscriber._error (Subscriber.js:64:30)
    at OperatorSubscriber.error (Subscriber.js:40:18)
    at OperatorSubscriber._error (Subscriber.js:64:30)
    at OperatorSubscriber.error (Subscriber.js:40:18)
    at Observable.init [as _subscribe] (throwError.js:5:45)
    at Observable._trySubscribe (Observable.js:37:25)
    at Observable.js:31:30
    at errorContext (errorContext.js:19:9)
    at Observable.subscribe (Observable.js:22:21)
    at catchError.js:14:31
    at OperatorSubscriber._error (OperatorSubscriber.js:23:21)
    at OperatorSubscriber.error (Subscriber.js:40:18)
    at XMLHttpRequest.onLoad (http.mjs:1850:30)
    at XMLHttpRequest.sentryWrapped (helpers.js:74:23)
    at _ZoneDelegate.invokeTask (zone.js:406:31)
    at AsyncStackTaggingZoneSpec.onInvokeTask (core.mjs:24002:28)
    at _ZoneDelegate.invokeTask (zone.js:405:60)
    at Object.onInvokeTask (core.mjs:24300:33)
    at _ZoneDelegate.invokeTask (zone.js:405:60)
    at Zone.runTask (zone.js:178:47)
    at ZoneTask.invokeTask [as invoke] (zone.js:487:34)
    at invokeTask (zone.js:1661:18)
    at globalCallback (zone.js:1704:33)
    at XMLHttpRequest.globalZoneAwareCallback (zone.js:1725:16)