Closed BryceAG closed 6 years ago
Associated error when testing with assertions:
phetioEvents.js?bust=1505840103863:160 Uncaught Error: Assertion failed: mismatched messageIndex, possible start/end mismatch
at window.assertions.assertFunction (assert.js:22)
at Object.end (phetioEvents.js?bust=1505840103863:160)
at SimIFrameAPI.js?bust=1505840103863:284
@BryceAG I know you probably made this in a hurry, but please don't forget to reference to the QA issue.
For phetsims/QA/issues/50
In deleteControlPoint
, if I comment out track.removeEmitter.emit();
then the problem goes away. Not sure why!
@zepumph and @phet-steele discovered this problem has the same nature as https://github.com/phetsims/phet-io/issues/1143
Our hypothesis is that a node start event is being called, but the node is deleted before the end can be called. Neither of us currently understands what the errant sequence is or what the correct sequence is supposed to be.
We worked around that problem with a setTimeout in https://github.com/phetsims/phet-io/issues/1143 and the same workaround works here too, but it is unclear why it works at all. It seems the setTimeout would just schedule the 'end' event for later on. Maybe so it can finish processing the input event?
@zepumph recommends finer-grained logging messages regarding pushing and popping so we can visualize what is happening here. Then we can determine if there is a better solution or if setTimeout is really appropriate.
@zepumph says it is OK to commit the setTimeout workaround for now, but we shouldn't let that defer us from understanding the deeper problem.
@samreid if it means anything, the State wrapper gives this error from simply clicking on a track node, no need to even cut it.
SimIFrameAPI Invocation Error: Error: Impossible set state:
energySkateParkBasics.playgroundScreen.view.trackNode_4.controlPointNode_1.controlPointUI
at energy-skate-park-basics_en-phetio.html?production&sim=energy-skate-park-basics&relativeSimPath&frameTitle=destination:1130
at Object.g [as setState] (energy-skate-park-basics_en-phetio.html?production&sim=energy-skate-park-basics&relativeSimPath&frameTitle=destination:1130)
at TPhETIO.implementation [as setState] (energy-skate-park-basics_en-phetio.html?production&sim=energy-skate-park-basics&relativeSimPath&frameTitle=destination:1130)
at Object.invoke (energy-skate-park-basics_en-phetio.html?production&sim=energy-skate-park-basics&relativeSimPath&frameTitle=destination:1130)
at Object.handleSingleInvoke (energy-skate-park-basics_en-phetio.html?production&sim=energy-skate-park-basics&relativeSimPath&frameTitle=destination:1130)
at Object.handleRequest (energy-skate-park-basics_en-phetio.html?production&sim=energy-skate-park-basics&relativeSimPath&frameTitle=destination:1130)
at energy-skate-park-basics_en-phetio.html?production&sim=energy-skate-park-basics&relativeSimPath&frameTitle=destination:1130 Error: Impossible set state:
energySkateParkBasics.playgroundScreen.view.trackNode_4.controlPointNode_1.controlPointUI
at http://www.colorado.edu/physics/phet/dev/html/energy-skate-park-basics/1.4.0-phetiorc.1/energy-skate-park-basics_en-phetio.html?production&sim=energy-skate-park-basics&relativeSimPath&frameTitle=destination:1130:52472
at Object.g [as setState] (http://www.colorado.edu/physics/phet/dev/html/energy-skate-park-basics/1.4.0-phetiorc.1/energy-skate-park-basics_en-phetio.html?production&sim=energy-skate-park-basics&relativeSimPath&frameTitle=destination:1130:52531)
at TPhETIO.implementation [as setState] (http://www.colorado.edu/physics/phet/dev/html/energy-skate-park-basics/1.4.0-phetiorc.1/energy-skate-park-basics_en-phetio.html?production&sim=energy-skate-park-basics&relativeSimPath&frameTitle=destination:1130:1421226)
at Object.invoke (http://www.colorado.edu/physics/phet/dev/html/energy-skate-park-basics/1.4.0-phetiorc.1/energy-skate-park-basics_en-phetio.html?production&sim=energy-skate-park-basics&relativeSimPath&frameTitle=destination:1130:1216383)
at Object.handleSingleInvoke (http://www.colorado.edu/physics/phet/dev/html/energy-skate-park-basics/1.4.0-phetiorc.1/energy-skate-park-basics_en-phetio.html?production&sim=energy-skate-park-basics&relativeSimPath&frameTitle=destination:1130:1215144)
at Object.handleRequest (http://www.colorado.edu/physics/phet/dev/html/energy-skate-park-basics/1.4.0-phetiorc.1/energy-skate-park-basics_en-phetio.html?production&sim=energy-skate-park-basics&relativeSimPath&frameTitle=destination:1130:1215620)
at http://www.colorado.edu/physics/phet/dev/html/energy-skate-park-basics/1.4.0-phetiorc.1/energy-skate-park-basics_en-phetio.html?production&sim=energy-skate-park-basics&relativeSimPath&frameTitle=destination:1130:1216610
I'll move the preceding comment to a new issue--it seems separate.
I added push/pop log statements and saw this:
PUSH: 1713: energySkateParkBasics.playgroundScreen.view.trackNode_4.controlPointNode_2.controlPointUI.deleteButton::fired
PUSH: 1714: energySkateParkBasics.playgroundScreen.model.tracks::itemRemoved
PUSH: 1715: energySkateParkBasics.playgroundScreen.model.editButtonEnabledProperty::changed
POP: 1715
PUSH: 1716: energySkateParkBasics.playgroundScreen.model.clearButtonEnabledProperty::changed
POP: 1716
POP: 1714
PUSH: 1717: energySkateParkBasics.playgroundScreen.model.track_5.physicalProperty::changed
POP: 1717
PUSH: 1718: energySkateParkBasics.playgroundScreen.model.track_5.droppedProperty::changed
POP: 1718
PUSH: 1719: energySkateParkBasics.playgroundScreen.model.tracks::itemAdded
PUSH: 1720: energySkateParkBasics.playgroundScreen.model.clearButtonEnabledProperty::changed
POP: 1720
POP: 1719
PUSH: 1721: phetio::stepSimulation
POP: 1721
PUSH: 1714: energySkateParkBasics.simIFrameAPI::invoked
POP: 1714
PUSH: 1715: energySkateParkBasics.simIFrameAPI::invoked
PUSH: 1716: energySkateParkBasics.playgroundScreen.view.trackNode_4.controlPointNode_2.controlPointUI.deleteButton::fired
PUSH: 1717: energySkateParkBasics.playgroundScreen.model.tracks::itemRemoved
PUSH: 1718: energySkateParkBasics.playgroundScreen.model.editButtonEnabledProperty::changed
POP: 1718
PUSH: 1719: energySkateParkBasics.playgroundScreen.model.clearButtonEnabledProperty::changed
POP: 1719
POP: 1717
PUSH: 1720: energySkateParkBasics.playgroundScreen.model.track_5.physicalProperty::changed
POP: 1720
PUSH: 1721: energySkateParkBasics.playgroundScreen.model.track_5.droppedProperty::changed
POP: 1721
PUSH: 1722: energySkateParkBasics.playgroundScreen.model.tracks::itemAdded
PUSH: 1723: energySkateParkBasics.playgroundScreen.model.clearButtonEnabledProperty::changed
POP: 1723
POP: 1722
POP: 1715
Assertion failed: mismatched messageIndex, possible start/end mismatch
PUSH: 1722: energySkateParkBasics.browserTabVisibleProperty::changed
POP: 1722
PUSH: 1724: energySkateParkBasics.browserTabVisibleProperty::changed
POP: 1724
PUSH: 1723: energySkateParkBasics.browserTabVisibleProperty::changed
POP: 1723
PUSH: 1725: energySkateParkBasics.browserTabVisibleProperty::changed
This confirms that the root of the problem is that controlPointUI.deleteButton::fired
pushes but never pops, and it is happening on the source and destination frame.
It looks like PushButtonModel.dispose disposes the endedCallbacksForFiredEmitter
, I wonder if that happens while that emitter still has listeners.
It looks like in https://github.com/phetsims/axon/issues/124 we decided that it is OK for Emitters to still have listeners when disposed.
Is it fair to say a button should not be disposed while it is in the process of firing? I added an assertion as such in my working copy.
In regards to the last time we dealt with this in https://github.com/phetsims/phet-io/issues/1143 (credit due to the master of finding old issues: @phet-steele). We found that the close button was calling hide
, but hide
was actually disposing the dialog. This was a bug, so we just detached the hide
and dispose
calls. I don't think that will be too much help here, but maybe. . .
A 4000ms fuzz test on the PhET brand sims did not reveal issues with this assertion, I'll probably commit it. But we should evaluate whether there are other kinds of things that need to not be disposed while they are processing.
Is it fair to say a button should not be disposed while it is in the process of firing?
I feel like that is a reasonable assumption, maybe we should try to bring this up for dev meeting to see what people think about best practices.
In the preceding commit, you can use ?log to see a detailed PUSH/POP message stream for the phetioEvents to help debug "message index out of order" sort of problems.
I also committed a change to PushButtonModel that it throws an assertion error if it disposes or fires while already firing. Now we need a nice way to address this for Energy Skate Park: Basics.
What if PushButtonModel was using the "single Emitter" paradigm for nesting, see https://github.com/phetsims/phet-io/issues/1203 -- would that fix this problem?
I used setTimeout
to avoid disposing a button from its own fire method. @jonathanolson or @pixelzoom can you think of a better way to avoid disposing a button from its own fire method?
What if PushButtonModel was using the "single Emitter" paradigm for nesting, see phetsims/phet-io#1203 -- would that fix this problem?
I don't know how it would fix it. Wouldn't it still have the same problem because the listener is being attached to the emitter's callbacksEndedEmitter
and called later (but it will be disposed before the call)?
Maybe it would be good to talk in person about this.
I used setTimeout to avoid disposing a button from its own fire method.
I'm not clear on why a button can't be disposed of from its own fire method.
I used setTimeout to avoid disposing a button from its own fire method. @jonathanolson or @pixelzoom can you think of a better way to avoid disposing a button from its own fire method?
Please don't use setTimeout, for the reasons it is banned from usage by our code review guidelines. That definitely should be able to screw up sim playback on its own.
I'm not clear on why a button can't be disposed of from its own fire method.
I can guess it's because it would dispose resources that would be used for sending phet-io events.
If this is the case, I'd (a) try to find a way for it to be OK to dispose from its own fire, or (b) figure out how to "queue" disposal if the event is happening, and check for this case (and dispose it) at the end of the event.
I'm not clear on why a button can't be disposed of from its own fire method.
PhET-iO relies on the "finished calling back button fired listeners" callback to close the "transaction". The button was getting disposed during firing callbacks and the transaction was never completing
I'd (a) try to find a way for it to be OK to dispose from its own fire,
Great idea @jonathanolson, perhaps if we detect that a dispose happens during firing, we can close the PhET-iO transaction.
I removed the setTimeout
and replaced it with code that completes the PhET-iO transaction, and it is working well. We should apply this strategy in other places with the setTimeout
workaround, such as the issue marked above. @zepumph do you know of other places with the setTimeout
workaround?
@samreid are we going to keep the assertion in https://github.com/phetsims/energy-skate-park-basics/issues/380#issuecomment-330721521 (I don't know if it's still being discussed or not)? It's being thrown in expression-exchange and scenery-phet, and so would need work to fix if we keep the assertion. Should I go ahead and report it?
Yes, I'd like to see how to reproduce the problem in Expression Exchange.
Referenced above.
@samreid are we going to keep the assertion in #380 (comment) (I don't know if it's still being discussed or not)?
The assertion was removed in phetsims/sun@3be19b7
@samreid the solution looks effective, elegant, and simple.
Are there any other places where we want this logic? What other ui components are allowed to dispose themselves while carrying out an event?
I don't think there are any other places where setTimeout is being used to delay a dispose. We used that only briefly in the about dialog issue above.
Are there any other places where we want this logic?
Perhaps we will find the other problematic cases during PhET-iO testing or fuzz testing (like how Energy Skate Park: Basics crashed). Additionally, in https://github.com/phetsims/phet-info/issues/59 we are discussing a lint rule to forbid setTimeout in sims, so perhaps that will catch other cases that got painted into this corner. Sound OK?
Sounds great. ready to close?
@phet-steele mentioned that this issue is probably related to https://github.com/phetsims/energy-skate-park/issues/8.
If I run http://localhost:8080/phet-io-wrappers/wrapper-template/wrapper-template.html?sim=energy-skate-park-basics&ea, pull out a track segment, then cut at the center control point, I see
Assertion failed: mismatched messageIndex, possible start/end mismatch
@zepumph this is the issue we were talking about this afternoon.
I am not seeing this problem in master. https://github.com/phetsims/energy-skate-park-basics/issues/415 made it so that PhET-iO events end properly, even for disposed objects. Closing.
When testing mirror inputs for phet-io and in playground mode, the mirrored sim will freeze if you try to separate the track at any joint. Found on Win 10, Mac, Chrome, Firefox, Safari, and Edge.