-
-
Notifications
You must be signed in to change notification settings - Fork 28
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
sync problem with a collection and document of overlapping paths #330
Comments
From @dsl101
|
If it's any consolation, I also see the weirdness when sometimes it works fine and sometimes it doesn't. There seem to be different mechanisms the firebase SDK uses in different scenarios—for example, I'm developing a Vue/Quasar app, and hot-reloaded changes see different results to refreshing the browser page, to refreshing with clear cache, to logging out and in again (firebase authentication). In my original post on the other thread, the |
on a local build, I comment out the entire part at:
I'm now 100% sure it's not related... If I, after auth listener triggers I execute: dispatch('company/openDBChannel', { companyId }, { root: true }).then(() => {
dispatch('companies/openDBChannel', null, { root: true })
}) then 50~80% of the time the second call will fail. that "companies" collection will execute with If I instead do: dispatch('company/openDBChannel', { companyId }, { root: true })
dispatch('companies/openDBChannel', null, { root: true }) just in parallel, then it works 100% of the time........ |
@dsl101 dispatch('company/openDBChannel', { companyId }, { root: true })
setTimeout(() => {
console.log(`waited 5 sec!`)
dispatch('companies/openDBChannel', null, { root: true })
}, 5000) now it's reproducible and someone can perhaps report to firebase js sdk. :D maybe I will if I have some time later! |
tracked down the bug to the firebase sdk level. I hope to find a workaround soon |
I've also been able to reproduce it in the browser—but apart from that I notice someone just picked up your issue though, so that's promising :) |
Making some progress in the firebase thread. Hope that they can look into it. Based on their solution/answer I will either way have to review how my library handles what happens in the onSnapshot listener. |
One thing is odd in the bug report. You say a prerequisite is to have persistence disabled (no cache). Then how could the first trigger batch of data come from cache? Did I miss something? |
Apart from this oddness, I'm starting to wonder if there actually is an issue. Yes, it's weird that sometimes it starts by a fromCache=true response if there is no cache, but when it does, there is a follow-up fromCache=false response which basically tells you "I have now checked with the server and there are no doc changes since the last times I gave you the docs from cache". |
Basically, the issue is more about having two realtime listeners with a same doc in common, and only one of them triggering an update, right? Maybe because the second one comes "from cache" from Firestore's point of view, and that we haven't thought of that case. Or maybe Firestore doesn't trigger anything at all on the second listener because somehow it considers we've been informed already. Can you please check with metadata changes enabled? As a side note, in the next version of vef, that won't be an issue anyway, as docs of a collection will be modules on their own, so there wouldn't be two modules storing the same data (which is a bad design choice to begin with imho, even if you felt it was simpler to handle at the time). |
This being said about problem 2: I'm more surprised by problem 1. When you say
What is it about exactly? One missing (which one, the one streamed in the other module)? Or several? |
@dsl101
this is a problem with how vuex-easy-firestore 1.0 is built and is difficult to fix with the current architecture. We'll mark this as
Yeah, I have no idea. I guess that's just how firebase works. It sometimes gives the server results marked You can replicate this sad truth about the weirdness of firebase, unrelated to v-e-f by following my reproduction steps here: Now, about problem 1... @louisameline I reviewed the code we have in place and I think, if we move the check for pending writes up and do nothing in that case: if (hasPendingWrites === true) {
// do nothing
} else if (fromCache === true) {
// always update docs in vuex state
} else {
// always update docs in vuex state
} Then we don't need to listen for the An abstraction looks something like this: However, the We need to keep in mind:
Because this is simply not true as we've found out. I'll hit you up on discord, let's discuss! |
I built a small test-case using native firebase SDK rather than vef, and, ignoring all the extra bells and whistles that vef provides (I'm only really interested in online, so no persistence, no metadata changes, etc.), I could bind a document and a collection separately, change either (or change it from the firebase console), and see all the changes I needed to see by simply responding to every To be honest, I'd even go for simply updating firebase (rather than patching Vuex locally first, and therefore saving the complication of rolling those local changes back on error). So it might be the case that I really don't need vef, but I'm always keen to use packages rather than re-invent the wheel; it may just be more than I need. I'm curious about the point of making collections bind each individual doc as a module—I'm dealing with collections of many hundreds of docs, and thinking the overhead of a module per doc could be high? But, if not, then perhaps that's an option in the medium term when V2 is available. |
We'll adapt yes and there already are cases where we know there will be unnecessary hook triggers indeed.
Absolutely, we are aware of that. Optimistic UI should be reserved to things that are easy to rollback. V2 will allow for the remote update before triggering the local update. And transactions. And many, many other cool things.
Currently, when you have a collection, you trigger actions on the collection to interact with one of its documents. The collection's document config, so to speak, is defined in the collection module config. This alone is already awkward if you think about it, and inconsistent with document modules.
Yes, we are aware of this, when you have hundreds of documents. I'm not sure what we'll do for that yet. Maybe keep the current behavior possible via an option, but not advertised as the "normal" way to handle things. The data would be kinda "read-only" though, and we'd instantiate a document module on-demand when you actually want to interact with a specific document. To be continued :) |
Just a question—how much of this complexity is due to managing the 'optimistic' update of the local state before sending data to firestore? I ask only because I've coded up a trivial implementation of vef to test against (all it does is bind a doc or collection, process snapshots, and allow updates via the firebase library calls). And I've noticed that the default behaviour seems to be to receive an Perhaps there's duplicated effort here in this case—my trivial library almost entirely suits my needs so I may just stick with it. Certainly it's not as comprehensive as vef, but I'm not using any hooks, persistence, or other 'advanced' features of firestore that vef abstracts. |
I don't understand what you are asking for? Anyway, you can always reinvent the wheel of course. It will be limited, buggy, you'll have to maintain it alone and you'll miss so many things you don't know you need yet, but it's possible. |
@dsl101 it's always healthy to weight the pros and cons of introducing a library into your codebase. To see if it does what you need it to and if it doesn't bloat your code too much. In your case perhaps writing your own library specific for your use case, is definitely a good option. However, as Louis mentioned, it might lead to you having to spend more time, doing something we already did. When it comes to this bug, today I implemented the onSnapshot listener for the next version of the library. Now I'm in a good spot to tweak the listener for version 1.0 so that this bug is fixed once and for all! I'll probably push the update tomorrow or the day after! 😉 |
You seem a little offended by my comment—certainly that wasn't my intention. As for reinventing the wheel, why not use vuexfire, which has been around since 2016 and is now part of the vuejs repo, rather than write vef? And I guess we wouldn't be here if vef was bug free... The point is to use exactly the right tool for the job. I'm not reinventing the wheel, just putting the correct tyres on. If my app grows in complexity to the point where I need lots of additional capability offered by vef or any other library, I will certainly assess that. In the meantime, I'm still keep to improve vef, understand what's going wrong here, etc. I think my question was a misunderstanding of this issue where @mesqueeb said "vuex easy firestore already has optimistic UI built in". I'd taken that to mean the vef was patching the vuex state in advance of getting the In any case, it turned out that my simple wrapper around the firestore SDK served my app's purpose, so why use something more complex than needed? |
Hey @dsl101 a quick note on the current status of the optimistic UI:
When it comes to the actual firebase SDK with which we make the batch call, that has its own cached data (used for it's native persistence etc.). The firebase SDK will in turn as well, update it's own local cache first, then sync to the server. Basically, when working with v-e-f, you end up with local data twice: once in vuex and once in the Firebase SDK. the difference is, the firebase SDK charges you each time you try to read that data, because it can only be read through get() and onSnapshot() calls, and will each time give you back its cache and then also make the server call. Which leads me to my next point:
I learned now that I made a small mistake in the past with how I handle the onSnapshot listener which manifested in this bug. But now I know how to fix it, so I'll do it very soon, hold on just 1-2 more days!
I hope this helps! 😉 PS: the reason I didn't use Vuex Fire and started building Vuex Easy Firestore, is because Vuex Fire had very bad documentation, and I wanted a different approach than what Vuex Fire was already doing. Also at that time I needed to have the flexibility to make sure it fits all my own needs, so I decided to just write something that fits all my needs. 😄 Then after a while I realised, I can open source my work so far, so others can enjoy it, and so vuex-easy-firestore was born. |
@dsl101 I'm not offended at all, no worries. I was just surprised that the advantages of v-e-f compared to Vuexfire were still unclear to you at this point. We'll definitely need to update the doc to make the advantages clear to everyone. From the top of my head, I'd say the key points are:
And there is other stuff in the works. Vef is clearly young and perfectible, but at some point there will be no possible doubt that it plays at another level.
When you enable Firestore persistence, and do things synchronously after a call to a Firestore SDK method (as usually indicated in their doc), you get "optimistic UI" yes. V-e-f mostly relies on that pattern for now, that's why v-e-f is also optimistic. Or you can wait for the promise returned by the method to resolve, for confirmation of the remote update. |
Tx for the replies—I've used vuexfire for that last few years with firebase, and decided to give vef a try when porting the app to firestore. But there are a number of things quite specific to my use case that do probably mean vef is more than I need right now (and probably the same is true of vuexfire since I didn't really know firebase / firestore very well at all when I started this). I don't need anything offline, and I'm only using Having said all that, I'm still keen to pin down the optimistic bit. I'm not using persistence, just a simple call to |
Yes, that's how it works. Even if you're offline,
Yes, unless you hold on to the promise that resolves after the actual update, and/or ask for With mesqueeb, there are a couple edge-case scenarios with weird behavior that we still need to understand, but that's roughly it. Check their doc, they give some info about that. |
@dsl101 problem 1 is fixed in latest version. problem 2 won't be fixed for v1.0 because it requires a complete rewrite of about half of the library, but it's already implemented for v2.0. |
I'm not sure about the new way if (docSnapshot.metadata.hasPendingWrites) return Imagine that you request a write to Firestore, and that it takes 5 seconds to perform. In the issue you raised to the Firebase team, I believe there was nothing wrong in your screenshot when I don't really understand what your problem was to begin with, I'd need a reproduction snippet, but I think it might only happen when It's obvious to me why it wouldn't work when it's |
Yeah, I'll force The cases I imagine you are thinking of is:
For me the main take-away from that thread was:
|
@louisameline I have reviewed your PR as well, but since the code of the onSnapshot listener is now very different it's difficult to merge. However, I have enabled The part where you are comparing snapshots I believe is already addressed by my changes here a while ago: |
The way I understood it, I remember we weren't using For the merge, if I'm right about |
I checked and I think my
My PR cleaned a few things on its own, it would be nice to have them merged. |
there seem to be some sync issues when there's a collection called
users
and a doc calledusers/{userId}
both loaded at the same time.problem 1. not all users get loaded
problem 2. user doc is not updated when that doc is updated through the users module and visa versa
related: #316
The text was updated successfully, but these errors were encountered: