12

In my app, a user can create a message and send it. When the user sends the message, the message is created with createRecord and the server replies with 201 Created if successful.

Also, the user can get messages from other users through a websocket. When it receives a message, I push it into the store with pushPayload.

var parsedData = JSON.parse(data);
this.store.pushPayload('message', parsedData);

The problem is, when a user sends a message and saves it, they also get it back from the websocket, and even though both objects have the same id, the store ends up with duplicate messages.

How can I tell the store than when I push or save something with the same id of an already existing element, it should override it?

Marc-François
  • 3,900
  • 3
  • 28
  • 47
  • According to http://emberjs.com/api/data/classes/DS.Store.html#method_pushPayload it should update records – Jakeii Apr 29 '15 at 19:45
  • 1
    It does, but only when the websocket response is delayed. I'm sure the problem is a race condition. Dealing with runloops seem to have fixed the problem, but I'll make sure before posting my answer. – Marc-François Apr 29 '15 at 20:56
  • As you mentioned, I think the run loop is suspect here. I would make sure that you're doing `Ember.run.next(function() { _this.store.pushPayload(....` so it executes after the record is initially persisted. In my experience, it can even be multiple run loops, in which case `Ember.run.later` with an arbitrarily long timeout will confirm this in troubleshooting. – mpowered May 04 '15 at 03:40
  • Not sure what your implementation looks like, but can you delay the websocket's push until at least after the server gives a response to the browser? It sounds a lot like your websocket server implementation is getting run synchronously instead of being pushed to queue as it most likely should. – mpowered May 04 '15 at 03:42

2 Answers2

3

Simply perform a check to see whether the model is already in the store before adding it:

var parsedData = JSON.parse(data);
if(this.store.hasRecordForId ('typeOfYourRecord', parsedData.id)){
    // logic you want to run when the model is already in the store
    var existingItem = this.store.find('typeOfYourRecord', parsedData.id);
    // perform updates using returned data here
} else {
    this.store.pushPayload('message', parsedData);
}
Oren Hizkiya
  • 4,420
  • 2
  • 23
  • 33
  • 2
    It only works when I tell the server to wait a second before notifying the users. I think otherwise the notification arrives too quickly and the save wasn't completed. I'll accept the the answer if it's the only way, but I'M surprised Ember Data allows duplicate records. There must be a way to push and override. I try the `update` method, but I got the same problem. – Marc-François Feb 09 '15 at 21:34
3

The only method I found to avoid this problem is to run my update in a new runloop. If the delay in ms in long enough, the problem won't occur.

It seems that receiving the update from the websocket and the request at nearly the same time creates a race condition in Ember Data.

Marc-François
  • 3,900
  • 3
  • 28
  • 47