mercredi 15 juillet 2020

Ember websocket/new object collision workaround clobbering hasMany promise

I have an Ember 3.8 app that uses Ember Data 3.8 and a websocket. We use the standard Ember Data API to preload data in Routes before processing, and for creating and deleting records. We also push all relevant updates to the database back to the browser through a websocket, where we pushPayload it into the store.

This pattern doesn't seem too uncommon - I've seen people discuss it elsewhere. A common problem with this pattern, however, is how to handle the collision when you are creating a record and the websocket sends down a copy of this new record before your POST resolves. Normally a pushPayload would simply update the record already existing with the payload's ID. For a record mid-save, the pushPayload creates a new record. Then when the POST returns and Ember Data tries assigning the ID to the pending record, it discovers there was already a record with that ID (from the websocket) and throws an exception.

To get around this we wrapped createRecord in some code that detects collisions and unloads the existing record with the ID so the pending record can be the true instance.

This worked well for a while, but now we're getting some odd behavior.

One of the models we create this way is the target of an async hasMany from another model. Example:

model-parent: {
 children: hasMany('model-child', {async: true}),
}

When we have a collision during a save of 'model-child', the PromiseManyArray returned by get('children') is destroyed, but the content of the PromiseManyArray is not. Further, the parent.get keeps returning this destroyed PromiseManyArray. Later we try binding a computed to it, which throws an exception trying to bind to the destroyed PromiseManyArray.

eg:

> modelParent1.get('children').isDestroyed
true
> modelParent1.get('children').content.isDestroyed
false
children: computed('modelParent1.children.[]')
^^^ blows up at controller setup time when trying to add a chainwatcher to the destroyed PromiseManyArray

I've tried reloading the parent object and also reloading the hasMany to get a 'fixed' PromiseManyArray but it still returns the broken one.

I know this is a pretty specific setup but would appreciate any advice for any level of our issue - the websocket collision, the broken hasMany, etc.

I wouldn't know where to being creating a twiddle for this, but if my workaround doesn't actually work I'll give it a shot.




Aucun commentaire:

Enregistrer un commentaire