meteorhacks / unblock

this.unblock inside publications :D
MIT License
87 stars 14 forks source link

this.unblock() makes publication return 0 results #11

Open SachaG opened 8 years ago

SachaG commented 8 years ago

Just ran into a weird bug where having this.unblock() in my publication makes it temporarily return 0 results when I paginate. This might very well be related to my own code, but here's a quick screencast to illustrate the problem just in case:

http://cl.ly/fAzd

Here's my publication code: https://gist.github.com/SachaG/ac2a775e3b770597171c

Oh and this is in Meteor 1.3 btw.

jacobparis commented 8 years ago

this.unblock() forces the publication to run asynchronously, which means your page will load without waiting for the publication to load.

SachaG commented 8 years ago

OK, but I still don't see why the post count would drop to 0 when using unblock?

queso commented 8 years ago

this.unblock() forces the publication to run asynchronously, which means your page will load without waiting for the publication to load.

This is inaccurate. The client never waits for anything. You can use Iron Router waitOn or template level subs with the reactive subscriptionHandle.ready() call to rerender as data updates.

My guess this is actually a problem based on how publish-counts is constructing things.

eugyev commented 7 years ago

I'm running into the same issue. I think I have an explanation. Essentially, when you rerun the same subscription with a reactiveVar that changed - meteor will create a new subscription and unsubscribe from the old one 'at the right time' - see here https://forums.meteor.com/t/when-do-subscriptions-get-unsubscribed/15862/3

I did this with DDP logging (using Meteor Toys) and here's what I see.
My page loads with Subscription1 with 10 records.
I click 'load more' which changes limit to 20 records.

Meteor then creates a new subscription, Subscription2, and sends a request to the server with that subscription. Right after that, it sends a request to 'unsubscribe' from Subscription1. So this is the same wether or not this.unblock() is present. What happens now depends on what's in the publication.

If I do NOT have this.unblock(), then Subscription2 runs, returns it's 10 records, and then Subscription1 is removed - because the publish function is blocking. The records from subscription1 are not removed, however, because it sees that Subscription2 is requesting them.

If I DO have this.unblock(), then while Subscription2 is fetching/finding, Subscription1 gets cancelled and I see requests to remove the objects (presumably because Subscription1 is saying 'I'm gone, and you don't have a new subscription with these same records, so remove them). After that Subscription2 returns it's results and sends back all 20 records.

I'm going to play around to see if I can fix this. It took a long time to sort this out, but this is a real problem if you are updating your subscription using reactive variables

Edit * - I haven't figured out an elegant way to fix this problem. I'm just removing the this.unblock() for now. It seems to only happen when the collection being searched is relatively large - which makes sense based on the above that if it's taking a while to make the publication cursor, the unsubscribe might happen too soon. Please let me know if anyone finds a better solution for this.

mitar commented 7 years ago

One workaround would be to use this my package which allows changing arguments to a query without restarting the subscription.

mitar commented 7 years ago

One option would be that the client side does not send unsubscribe until the new subscription responds with ready (or error). Currently unsubscribe is send immediately and we depend on the server to process those messages in order. In a way we could see this is as a subscription manager's job on the client. To delay unsubscriptions a bit.