Listening on server side models

143 views
Skip to first unread message

ryan alexander

unread,
Sep 17, 2012, 4:32:05 PM9/17/12
to der...@googlegroups.com
What is the correct way to do it? More specifically, I only want to
listen on changes sent over socket.io, and respond by setting some
data. None of the examples that I've found do something like this, so
I'm turning to the list!

I tried a few ways.. Listening on req.getModel() doesn't work at all
for client changes. Listening on a subscription to store.createModel()
works, but causes the change history to be repeated every 10 seconds.

I made a gist here with a more detailed description and code:

https://gist.github.com/3739541

It'd be awesome if someone familiar with Derby can take a look at it
and point me in the right direction. I suppose it's also possible that
this is just unsupported behavior, which would also be really nice to
know.

Thanks!
ryan

# Ryan Alexander
# http://onecm.com

Nate Smith

unread,
Sep 17, 2012, 5:01:12 PM9/17/12
to der...@googlegroups.com
Hi Ryan,

It's possible to create models on the server for use in initialization and server-side rendering. However, models have their own copy of the data to which they are subscribed, so they are not meant to be long-living. Keeping a model around beyond the initial render would eventually lead to large memory leak problems.

It does not make sense to use the model for a given request (from req.getModel()), because such a model gets created, initialized, and bundled to send to the client within processing the request. After the page is rendered, that model cannot be maintained on the server, because it will eventually be re-initialized on the client. The same model cannot exist in two places at the same time or lots of data conflict issues would occur.

Not exactly sure what is going on with the transactions being repeated when you create a model from the store directly, but its possible there is a bug with transaction acknowledgement from long-lived models on the server. Also, you probably shouldn't ever subscribe to "*", as it would mean that the model would maintain a copy of all data ever stored.

For server-side only logic, all operations should be done using the store only. The store is an interface directly to the database and does not maintain a separate copy of the data. Store mutators have a router system based on model paths that is not documented yet.

There is a way of creating listeners on the store but the API will probably change. Currently it looks something like:

store.afterDb('set', 'items.*', function(txn, doc, previousDoc, done) {
  ...
  done()
});

Inside of the callback you can call mutator methods like "store.set"

- Nate

ryan alexander

unread,
Sep 17, 2012, 7:31:38 PM9/17/12
to der...@googlegroups.com
Thanks for the explanation, Nate. This clears things up quite a bit.

Trying this out, though, I'm still seeing the messages repeat every 10
seconds, even when setting on the store directly:

store.afterDb('set', '*', function(txn, doc, previousDoc, done) {
if(txn[1].charAt(0) != '#') { // Local updates seem to start with '#'
store.set('result', 'hello', function(){})
}
done()
})

Meanwhile console prints:

3d85ac75-c24a-4335-948c-ba403dc7296e ↩ Connect
3d85ac75-c24a-4335-948c-ba403dc7296e ↪ Asking client to request a
snapshot update of new transactions
3d85ac75-c24a-4335-948c-ba403dc7296e ↩ Derby app with hash
7jZswxG7t1BoXEuNbXalEw
3d85ac75-c24a-4335-948c-ba403dc7296e ↩ ver: 0 - set 'a', ''
3d85ac75-c24a-4335-948c-ba403dc7296e ↪ ver: 2 - set 'result', 'hello'
3d85ac75-c24a-4335-948c-ba403dc7296e ↩ ver: 2 - set 'a', '1'
3d85ac75-c24a-4335-948c-ba403dc7296e ↪ ver: 4 - set 'result', 'hello'
// 10 seconds later...
3d85ac75-c24a-4335-948c-ba403dc7296e ↩ ver: 1 - set 'a', ''
3d85ac75-c24a-4335-948c-ba403dc7296e ↪ ver: 6 - set 'result', 'hello'
3d85ac75-c24a-4335-948c-ba403dc7296e ↩ ver: 3 - set 'a', '1'
3d85ac75-c24a-4335-948c-ba403dc7296e ↪ ver: 8 - set 'result', 'hello'
// 10 seconds later...
3d85ac75-c24a-4335-948c-ba403dc7296e ↩ ver: 5 - set 'a', ''
3d85ac75-c24a-4335-948c-ba403dc7296e ↪ ver: 10 - set 'result', 'hello'
3d85ac75-c24a-4335-948c-ba403dc7296e ↩ ver: 7 - set 'a', '1'
3d85ac75-c24a-4335-948c-ba403dc7296e ↪ ver: 12 - set 'result', 'hello'
// 10 seconds later...
3d85ac75-c24a-4335-948c-ba403dc7296e ↩ ver: 9 - set 'a', ''
3d85ac75-c24a-4335-948c-ba403dc7296e ↪ ver: 14 - set 'result', 'hello'
3d85ac75-c24a-4335-948c-ba403dc7296e ↩ ver: 11 - set 'a', '1'
3d85ac75-c24a-4335-948c-ba403dc7296e ↪ ver: 16 - set 'result', 'hello'

# Ryan Alexander
# http://onecm.com


Nate Smith

unread,
Sep 17, 2012, 7:51:24 PM9/17/12
to der...@googlegroups.com
Looks like set is actually being invoked multiple times in the client. Perhaps the issue is in your client code.

ryan alexander

unread,
Sep 17, 2012, 8:10:21 PM9/17/12
to der...@googlegroups.com
Hm.. My client code does almost nothing, just subscribes to "result"
on the model. I stripped down the test to a minimum just to be sure:

https://gist.github.com/3740535

# Ryan Alexander
# http://onecm.com


ryan alexander

unread,
Sep 18, 2012, 1:56:29 AM9/18/12
to der...@googlegroups.com
I made a git repo for this test case:

https://bitbucket.org/notlion/derby-test/src

Maybe moving this to GitHub issues is warranted. Think it's a bug?

ryan

# Ryan Alexander
# http://onecm.com


ryan alexander

unread,
Sep 19, 2012, 1:52:55 PM9/19/12
to der...@googlegroups.com
I got this to work last night. Turns out if done() is called *first*,
there are no repeat messages:

store.afterDb("set", "*", function(txn, doc, prevDoc, done) {
done()
if(txn[1].charAt(0) != "#") { // Don't set on local changes.
store.get("a", function(err, a) {
store.get("b", function(err, b) {
store.set("result", +a + +b)
})
})
}
})

After digging around a little, I'm still not familiar enough with
Derby / Racer's internals to know why this is the case, but hey it
works for now :)

I'll go ahead and update the test repo just in case it's useful.
Thanks very much for the help!

ryan

# Ryan Alexander
# http://onecm.com


Rom

unread,
May 24, 2014, 6:56:16 AM5/24/14
to der...@googlegroups.com, na...@nateps.com
Hi all

How is that done today with the Derby 0.6 version?


Rom

unread,
May 24, 2014, 7:13:24 AM5/24/14
to der...@googlegroups.com, na...@nateps.com
Have been searching for this and found some answer on the forum that might help others in the near futur :

On the server side, I can track changes on the model with the following steps :

- get an instance of the model from the store
- subscribe to the desired data
- detect the changes

So an example would be this code extract, where "admin" is a path in mongodb :

    // server side model watching
    var model = store.createModel();
    // subscribe to changes
    model.subscribe('admin', function(err, msg){
      model.on('change', 'admin.*', function(id, message) {
        console.log("Change detected on the model from the server side!");
      });
    });

In the view, if I change any info in the mongodb path "admin", the server will detect the change and trigger the console.log. So an action like this would do it trigger it :

    model.root.set('admin.lastsync', Date());

Hope it helps anyone. 

Cheers

Artur Zayats

unread,
May 24, 2014, 1:34:10 PM5/24/14
to der...@googlegroups.com, na...@nateps.com
Yes, also you can use hooks - look at https://github.com/zag2art/derby-hook

Rom

unread,
May 24, 2014, 2:19:37 PM5/24/14
to der...@googlegroups.com, na...@nateps.com
Thanks Artur. I might have a look at this hook feature. But I got the version I mentioned earlier working very well!
Reply all
Reply to author
Forward
0 new messages