-
Notifications
You must be signed in to change notification settings - Fork 2.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Optimistic mutations should only update store once if optimistic result was correct #3691
Comments
There seems to be a similar discussion for relay here that may be of interest. facebook/relay#2481 |
yes, and luckily apollo is one step further along for implementing it :)
let's
…On Fri, Jul 20, 2018, 5:01 AM Josh Ribakoff ***@***.***> wrote:
There seems to be a similar discussion for relay here that may be of
interest. facebook/relay#2481
<facebook/relay#2481>
—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
<#3691 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AADWlhhauH6dizUOUyt66hkGqk9VaxOKks5uIUgfgaJpZM4VQMkM>
.
|
What about failures? If I send 5 increments and and 5 are in flight, then the first one fails, then what happens? Should it rollback the other 4 optimistic responses? They would all be wrong (off by one). Also I think I found a pathological case where your proposed fix would cause issues:
The count appears to revert from 5 to 3, going backwards... Additionally we'd show 4 in the UI at the end of this sequence instead of showing 5, which is wrong. Instead maybe we can do this...
If at any time there are multiple in flight mutations and a mutation's actual response is received and it differs from its corresponding optimistic response, then we Or in other words if at any time things differ, we just block all updates until all requests settle, avoiding superfluous jumps. You don't know what data structure is being updated or any of its properties. It may not be a contiguous linear counter. It may be subject to complex business logic on the server. Another approach is to let users specify an immutable update method, and substitute previous optimistic values with their correct values as they arrive, and continually re-run all pending operations' immutable reducers to compute a new optimistic state. This would require a breaking API change unless it was optional / opt-in only.
Thats basically operations vs. state updates... For all mutations, it could use the "pessimest mode" algorithm and toggle between pessimistic / optimistic mode. Once all in flight requests settle, it would always switch back to optimist mode. For the subset of mutations that are state updates - The We should also update the docs. It should be clear to people reading the documentation how this all works exactly. A counter is a rather basic example and right now its not clear in the docs how this works. That could deter people from using apollo, or worse people could write code with the wrong assumptions in mind. It should be clear in the docs what assumptions can be made about how the state changes over time and in corner cases not just the happy path. |
@joshribakoff Oops missed this. If the server does not send the expected optimistic response, then the cache should instead show the server response. The pathological case you show is indeed a problem - to summarize, a bunch of mutations are sent, a couple of them fail resulting in an updated cache but the final mutation has the expected result, so it won't put that new result in the cache. This seems like an edge case, so your "pessimistic mode" proposal looks ok. I think the safest way to implement it is to mark all in-flight mutations as pessimistic, not just the ones for that query. I'm not sure about the other things you propose, I don't use the apollo state stuff. Note thought that in-flight mutations that already departed should never be cancelled, since you don't know if the network request already went to the server. So to summarize:
|
Any word on this from the team? It seems like a necessity if we want apps that are tolerant of intermittent connectivity,. At the moment, users will watch their offline, already-optimistically-rendered changes get rewound and replayed when they regain connectivity. That's a pretty terrible experience if they were in the middle of doing something. @wmertens suggestion sounds extremely reasonable and useful. |
Please try a recent version of |
2 years for a disappointing response. Apollo's lack of attention to detail on these types of edge cases make me not want to use the library on future projects, if I have a choice. |
@joshribakoff Have you tried |
@hwillson no because I no longer work at Twitch where we used it I work in the autonomous vehicle industry now and we don’t use gql. I empathize, but please understand I tried to be a contributor and help your small team but PRs sat, issues lingered, and Apollo could do a better job of working together with he community. If it were my lib, I would personally verify if the issue was fixed because I’d want my lib to be high quality and not blow up at runtime on people, which was something that has occurred in the past when using Apollo, and when trying to clarify these edge cases Apollo has been silent historically |
For sure @joshribakoff - all valid points. Thanks for the feedback! |
TL;DR:
Intended outcome:
Increase a counter via optimistic UI. Every click instantly shows the new value, and there is no glitching as server results come back.
Actual outcome:
Mutations always update the store with the result, so the counter will glitch back to the server result.
How to reproduce the issue:
schema:
The mutation for inc calls
mutate({optimisticResponse: count+1})
(plus the function to update the count in the cache).Here's what
count
will be when you click it once:and repeatedly:
The solution is that the mutation should check if the
response
from the server is equal to theoptimisticResponse
, and if so, leave the store unchanged. This would result in this:If somewhere along the way the server decides the answer is different, you get
So in this case, there are jumps, but never backwards
Note that if the server would not use
inc
butset
, it messes up the final value (should be 5):The text was updated successfully, but these errors were encountered: