-
Notifications
You must be signed in to change notification settings - Fork 412
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
onBeforeAction runs endlessly #742
Comments
I guess this relates to #741 |
It's possible there's an infinite invalidation loop. It's been reported in a few places. There will definitely be a workaround to prevent it. But then the deeper question is can we prevent users from getting into this situation in the first place somehow. But need to see some code so I can reason about it. |
I guess this reproduces the problem. Basically it is the client side join in an onBeforeAction. |
One workaround seems to work if you use the waitOn function for the "main" subscription. Then subscribe to all depending subscriptions in a onBeforeAction. But this does not work if you want to use subscription in global onBeforeActions or have more than one subscription you might want to "join". |
Thanks very much for the reproduction @DerMambo. Very helpful. The issue is that you are waiting on a new subscription at the same time as calling An easy work around is to not wait on the child subscriptions. @cmather I've added a failing test to IR/wait_list that highlights the problem. Haven't really thought too hard about a solution but I thought I'd wait for your thoughts. |
Happy to work it out on my own if you don't have time to think about it -- assign it back to me if so. |
Ok cool thanks guys. Will take a look on the next cycle shortly
|
@tmeasday, Can you summarize the issue? Is there an infinite loop created here somehow? |
Yeah. You can see in https://github.com/EventedMind/iron-router/blob/devel/test/client/wait_list.js#L58-L70 that the autorun runs endlessly (we bail out after too many iterations to avoid infinite loops). @DerMambo's reproduction caused an infinite loop directly in IR. |
Got it. Looking at this today. |
It looks like there's a few issues here:
From a var waitlist = new WaitList;
var handle = new Blaze.ReactiveVar(false);
Deps.autorun(function () {
waitlist.ready();
waitlist.wait(function () { return handle.get(); });
}); What should the expected behavior be? The current behavior is an infinite invalidation loop. The reason for this can be explained with these steps:
One potential solution is to not allow |
One potential solution is to only deprecate the _notReadyCount in an afterFlush callback. https://github.com/EventedMind/iron-router/blob/devel/lib/client/wait_list.js#L67 So the code would look like: if (cachedResult === false) {
Deps.afterFlush(function () { self._notReadyCount--; });
} This would allow the count to stay the way it was for one flush cycle, preventing the infinite loop. But not sure how to prove correctness here. @tmeasday, thoughts? |
@tmeasday, I think your test case is incorrect but not sure. Take a look at this example and see if that behavior makes sense to you. Reference: - iron-meteor/iron-router#742
@cmather — this exhibits my suspicion that decrementing the `notReadyCount` in the `afterFlush` is “too late”. One potential solution would be to do `deps.changed()` in the `afterFlush` if `notReadyCount` gets to 0 but I feel like that would just open a whole other kettle of fish.
@cmather I took another look at this particular issue and I realise that in fact and infinite loop is the expected behaviour, as we are essentially altering readiness inside a ready check. I think the failing test cases should still be fixed however. |
Expected, but probably fixable :-) doing a dep change in an after flush could fix it. And I guess since I'm using a counter the ready() value should always be up to date. Looking forward to checking out your solution.
|
Is it fixable? The code can be boiled down to:
Wouldn't the expected behaviour here be:
Seems like a classic infinite loop, ala setting + reading the same session var in the same autorun. I know that it's probably easy to make this kind of mistake in subtle ways (and maybe we can detect it and log something helpful), but fundamentally, how can we fix it without breaking the waitlist's behaviour? |
Repeating my comment from the other commit: I think the right approach is to detect this condition and throw an error. I have an implementation locally that I will try to push either tonight or when we get back from our family trip. The gist is: When a user calls wait() make sure the current computation or any of its ancestors is not already tracked as a dependent. If so, throw an error with suggested fixes which include:
|
Sounds reasonable. Still think we have to change the dep in the |
Users are finding themselves in a situation of infinite invalidation loops. This can happen if you call this.ready() and then subsequently add functions to the list which change the state in the same computation tree. Fix: When you call wait(...) see whether we already have a dependency on the current computation or any of its ancestors and if so throw a helpful error message. For example: var list = new WaitList; Deps.autorun(function () { list.ready(); Deps.autorun(function () { list.wait(...); // throw error }); }); Issue #742 cc @tmeasday, @DerMambo
@tmeasday, can you explain what you mean by this.ready() could be "wrong" in autoruns? I think I know what you mean (explained below) but I'm getting confused by the "change the dep in the onInvalidate" solution so I might not be understanding the problem. One problem I see here is that in the onInvalidate callback I decrement _notReadyCount and pull out the inner computation from the list. It's possible that the active comp is invalidated and any code that calls Given the above, the rule that |
In 0.9.1 this condition should throw an error and ask you to isolate your |
Hi,
i have a onBeforeAction that uses this.subscribe(...) and also reactive Session vars and also calls pause() at some time. It all works well on 0.8.2 with IR 0.7.1.
Also I log a simple this.ready().
At some point, I guess when the reactivity kicks in, the onBeforeAction runs endlessly and the log says this.ready() = true.
Is this a known issue? Something to do about it? Reproduction needed (I think I could do it over the weekend, maybe)?
The text was updated successfully, but these errors were encountered: