SocketCluster / socketcluster

Highly scalable realtime pub/sub and RPC framework
https://socketcluster.io
MIT License
6.14k stars 313 forks source link

Writting to store and fetching information from them. #75

Closed madwill closed 9 years ago

madwill commented 9 years ago

Thanks so much for creating such a powerful server for sockets.

Hope its ok to post this as a issue, i could not find a forum or irc channel. I could not find an explicit example on how to store information on the Stores.

Like a user list of a chat logs. The kind of information a user would get initially when entering a room. Can be larger then stream message but only sent once.

I usually do this through RPC. I was thinking this information should be on the stores since the worker should not share the state and would not know about each others.

Do you have any example where you write and retrieve data from the stores ?

One solution i believe could work would be

Is that retarded ? did i miss the API to do such a thing in a more streamlined way ?

i'm fairly new to sockets and node. But it looks like very exiting technology.

Cordially

William

jondubois commented 9 years ago

@madwill There are many ways to do this.

Also note that the store (nData) isn't the only way to store data, you can also use a database of your choice or Redis (may depend on your scalability needs). If you want to scale SC across multiple hosts, then you need to store that data in a scalable database like MongoDB, Cassandra or perhaps an SQL one - Stores aren't yet automatically scalable across multiple hosts (although you can certainly do your own replication if you like).

If you want users to listen to shared channels then you shouldn't have the username be part of the channel name. Only if it relates to that user specifically (maybe that's your case?).

If you want to keep track of logs, you should do it from the server side. There are several ways to do this. Here is some server code to give you ideas (note that I haven't tested this code) - In this example, we have a chat room about 'cats':

// Server code

wsServer.on('connection', function (socket) {
  // ...
  socket.on('POST cats', function (message, res) {
    // Append the message to a room_cats array inside the store
    // The array will be created automatically if it doesn't already exist.
    // Note that the res callback is in the form res([err, data]) which happens
    // to match the signature required by the nData **add** method:
    // callback([err]) https://github.com/topcloud/ndata#add
    wsServer.global.add('room_cats', message, res);

    // Publish the message globally to the cats channel so that
    // all client subscribers will receive it
    wsServer.global.publish('cats', message);
  });

  // In case client wants to get the whole list from scratch
  socket.on('GET cats', function (message, res) {
    wsServer.global.get('room_cats', res);
  });
  // ...
});

So then on the client side you can have:

// Client code

var catsChannel = socket.subscribe('cats');
catsChannel.watch(function (message) {
  // Display any new messages published to 'cats'
});

// The 'status' event gets triggered directly after the socket 
// connects (including reconnects due to failed connections)
// so it's a good place to request entire lists from scratch.
// It's also a good way to make sure that you haven't missed any messages
// while your connection was cut.
socket.on('status', function () {
  socket.emit('GET cats', function (err, messageList) {
    // ... render the list of all messages
  });
});

// ... This would probably run from an event handler of sorts
// Send a new message to cats channel
socket.emit('POST cats', 'I like cats!', function (err) {
  if (err) {
    alert('Failed to post message about cats because of this error: ' + err);
  }
});
// ...

You will probably need a way to clean-up/manage the cats list in the store so that it doesn't get too long. Also, you don't need to use the 'GET', 'POST' convention if you don't want - There are no formal conventions for doing this yet but hopefully it illustrates the point).

madwill commented 9 years ago

It does illustrate the point!

Thank you.

What i was looking for was:

wsServer.global.add(['rooms', 'cats'], message, res); wsServer.global.get(['rooms', 'cats'], res);

So i can share information between workers. The rest should be easy. The "username channel" was only to be able to find the way back to the initial connecting user. But its absolutely non necessary if i can access the store synchronously with globals.

Any draw back to this ? Does it slow down requests and potential overall performances ?

Perhaps this works like cluster hub ? https://github.com/fent/clusterhub ? With in memory key/value pairs synced through the all workers ? So under the hood it its non blocking.

Thanks again!

Ps: It would be nice to add a get and set in the socketCluster example app that comes with creating a new app for newcomers in this technology.

Since your service appeal to the "user friendly" crowd.

madwill commented 9 years ago

I guess it could possibly work with https://github.com/jondubois/socket.io-ndata now that i look at your profile :)

jondubois commented 9 years ago

@madwill socket.io-ndata is an old project. fent/clusterhub is also kind of old - Both of these are meant to work with the old version of Socket.io and none of them are scalable.

madwill commented 9 years ago

Ok.

My previous experience is with Java, which if we were to put a synchronized data storage in threads you would defeat the thread purpose.

I'll have a look at how global object works. Try and understand how data in globals can be shared between multiple workers.

Merci pour tous.