only run piggybacked operations after SR is finished, and isolate them #482
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Type of PR (feature, enhancement, bug fix, etc.)
Bug fix
Description
Piggybacked operations would run for all tabs, which is a problem for isolation mode. Also, there could be a race condition where piggybacked operations might start running before SR operations are completed.
This PR fixes both issues.
Post-script
This ended up being a lot more involved than I originally anticipated. The primary change ended up requiring that I modify the
method_missing
incable_ready_channels.rb
so that thereflex_id
is added to the options for every operation. The client then compares thereflexId
attached to the operation against thereflexes
dictionary to decide whether it should be executed on the current tab context. It seems like a viable solution but there could be cases I haven't considered. Would appreciate more brains on this.I've spent the last few hours attempting to isolate and address a 2nd race condition that emerged when sending CR broadcasts inside a Reflex. It seems like the path to
CableReady.perform(data.operations)
on line 105 ofreflexes.js
is super short, right? Not only is the WebSocket message with the CR broadcast sent before the morph broadcast, but thereflexOperations
on line 101 kicks off a multi-stage process involving several events and potentially DOM updates... and yet! somehow, the question of whether line 101 or 105 fires first is non-deterministic. I'm at a complete loss to explain this phenomena. ApparentlyObject.entries
(line 104) is slow, but it was happening even when I commented out line 104... and come on, it's not that slow.Still, you can't argue with observable, repeatable observations. If I wrap line 101 in a
setTimeout(,5)
the problem goes away about 99% of the time, although I still saw 1-2 show up out of order. As of right now, I've taken this as far as I can.What I plan to tell people is that if the order of operations is critcal, eg. that it must be
... then they should follow their
cable_ready
calls with asleep 0.01
tosleep 0.1
so that the CableReady broadcasts have a good chance to finish before the morph returns.In other words, this will work:
but if you need to guarantee that the
console_log
executes before the morph returns, you're looking at:In order to make this work reliably without
sleep
calls (although still non-deterministically ordered) I had to go ahead and comment out (former) line 74 oflifecycle.js
which removed completed reflexes from thereflexes
dictionary. This is something I already planned to do in the next major version of the library, and there's no obvious downside although long-running applications might start to occupy memory if lots of Reflexes are used. (The plan is for the next major version to have a reaping strategy, sort of like how Redis has a key expiration strategy. Hopefully, this will be fine without reaping until the next version is ready.)Final thing: in
channel.rb
on line 100 I added a safe navigation operator to the Reflex logger print statement. This means developers will be able to suppress server-side logging for a single Reflex if their Reflex action method contains@logger = nil
.Why should this be added
Race issues are bad.
Checklist