I'm working on an angular/node app where people can have many 1:1 chats with other users (like Whatsapp without groups) using socket.io and btford's angular-socket module (https://github.com/btford/angular-socket-io). Right now A) a client joins a socket.io room using emit. The client code is:
mySocket.emit('joinroom', room);
Server code is:
socket.on('joinroom', function (room){
socket.join(room);
});
B) chat messages are sent to server via emit. Client code is
mySocket.emit('sendmsg', data, function(data){
console.log(data);
});
and C) the server should send messages to others in the room via broadcast. Server code is:
socket.on('sendmsg', function (text, room, sender, recipient, timestamp) {
// Some code here to save message to database before broadcasting to other users
console.log('This works');
socket.broadcast.to(room).emit('relaymsg', msg);
});
Client code is
$scope.$on('socket:relaymsg', function(event, data) {
console.log('This only sometimes works');
// do stuff to show that message was received
});
A and B seem to work fine, but C seems to be very unreliable. The server code seems to be ok, but the client does not seem to receive the message. Sometimes it works, and sometimes it does not. ie 'This works' always shows up, but 'This only sometimes works' does not always show up.
1) Any thoughts on what could be causing this issue? Are there any errors in my code?
2) Is broadcast and rooms the right way to be setting this up if there are many users, all of which can have multiple 1:1 chats with other users?
In case it helps, this is the factory code for the angular-socket module
.factory('mySocket', function (socketFactory, server) {
var socket = socketFactory({
ioSocket: io.connect(server)
});
socket.forward('relaymsg');
return socket;
});
Appreciate any help you can provide!! Thanks in advance!
Thanks everyone for the comments, I believe I found the main issues. There were two things I think causing problems:
1) The bigger issue I think is that I'm use node clusters, and as a result users might join rooms on different workers and not be able to communicate with each other. I've ended up adding sticky sessions and Redis per the instructions here: http://socket.io/docs/using-multiple-nodes/
Sticky sessions is pretty useful, just as an FYI since the docs don't mention it, the module automatically creates workers and re-spawns them if killed
I couldn't find a ton of examples of how to implement sticky+redis since socket.io 1.0 is relatively new and seems to deal with Redis differently from prior versions, but these were very helpful:
https://github.com/Automattic/socket.io-redis/issues/31
https://github.com/evilstudios/chat-example-cluster/blob/master/index.js
2) Every time the user closed their phone it would disconnect them from the chat room, even if the chat room was the last screen open on the phone
Hope that helps people in the future!
Related
We are using pubsub & a cloud function to process a stream of incoming data. I am setting up a dead letter topic to handle cases where a message cannot be processed, as described at Cloud Pub/Sub > Guides > Handling message failures.
I've configured a subscription on the dead-letter topic to retain messages for 7 days, we're doing this using terraform:
resource "google_pubsub_subscription" "dead_letter_monitoring" {
project = var.project_id
name = "var.dead_letter_sub_name
topic = google_pubsub_topic.dead_letter.name
expiration_policy { ttl = "" }
message_retention_duration = "604800s" # 7 days
retain_acked_messages = true
ack_deadline_seconds = 600
}
We've tested our cloud function robustly and consequently our expectation is that messages will appear on this dead-letter topic very very rarely, perhaps never. Nevertheless we're putting it in place just to make sure that we catch any anomalies.
Given the rarity of which we expect messages to appear on the dead-letter-topic we need to set up an alert to send an email when such a message appears. Is it possible to do this? I've taken a look through the alerts one can create at https://console.cloud.google.com/monitoring/alerting/policies/create however I didn't see anything that could accomplish this.
I know that I could write a cloud function to consume a message from the subscription and act upon it accordingly however I'd rather not have to do that, a monitoring alert feels like a much more elegant way of achieving this.
is this possible?
Yes, you can use Cloud Monitoring for that. Create a new policy and perform that configuration
Select PubSub Topic and Published message. Observe the value every minute and count them (aligner in the advanced option). Now, in the config, when it's above 0 from the most recent value, the alert is raised.
To filter on only your topic you can add a filter by topic_id on your topic name.
Then, configure your alert to send an email. It should work!
user story:
We need to alert the user when there a modification or a comment on the thing he has posted by another user.
We are new to react and we are lost in a loop about how to notify the user who is logged in on a different page (maybe his dashboard). The event is performed by another user2 where he is on a page where is commenting on the thing posted by user1.
How can we send an alert to that user1? who currently on a different page saying "there is a new comment on your post".
The issue we are thing about is: The event happens on the comment page. We can send the alert on that comment page. But how will we be able to send a notification to other users on a different page?
I know there is already present. You can take Jiira Board as an example.
Could anyone let us know how can we implement this?
One option is to use WebSockets. Whenever a user is on a page where you'd want them to be able to get a notification, open a websocket to your server:
const socket = new WebSocket('https://my-server.com/socket');
On your server, set up the socket endpoint. Whenever one user sends a message to another, on the server, for all sockets currently opened by the receiver, send a socket message informing them of the new message. Eg, on the server:
activeSockets
.filter(({ userId, socket }) => userId === receiverId)
.forEach(({ socket }) => {
socket.send('You have a new message');
});
And listen for those messages on the client:
socket.addEventListener('message', ({ data }) => {
if (data === 'You have a new message') {
alert(data);
}
});
This is, in broad terms, the industry standard for this sort of thing; it's what Stack Exchange does. It's how many websites allow the server to send data to the client without (inelegant) polling.
Is it possible to implement a gatling test with multiple clients? Example: The first client gets a key which is communicated to the second client. That key is then used until the second client is finished and the first client can then proceed and check to see the result.
Cookies are the problem why I'm having troubles implementing this as a single client posing as two separate. The clients must have different set of cookies.
Alternatively; can I hold and reinsert the cookies for the first client?
I was able to circumvent the problem be storing and restoring the whole cookie jar like this:
val builder = scenario("Thingies")
... do some first client stuff
.exec(session => {
session.set("first-session-cookies",
session("gatling.http.cookies").as[CookieJar])
})
... do some second client stuff
.exec(session => {
session.set("gatling.http.cookies",
session("first-session-cookies").as[CookieJar])
})
... back to first client stuff
Works like a charm :-)
I would like to send messages to Pidgin chats or set chat topics via dbus. Following this guide I was able to write some pretty straightforward code to do just that, and it does indeed result in messages appearing or chat topics being changed... but it only seems to affect my window, without the other participants being aware of any messages or topic changes.
I'm using
purple.PurpleConvChatSetTopic(chat_data, user, topic)
and
purple.PurpleConvChatWrite(chat_data, user, message, flag, time)
I don't think this is due to any misuse of the dbus api as the calls actually result in actions. I just wonder if I need to perform some sort of authentication first? Or maybe the user can only be the current user? I tried with my nick and also setting it as unicode but to no avail.
Here is the complete code anyway:
import dbus
import time
# define chat_name, user, topic, message
bus = dbus.SessionBus()
obj = bus.get_object('im.pidgin.purple.PurpleService', '/im/pidgin/purple/PurpleObject')
purple = dbus.Interface(obj, 'im.pidgin.purple.PurpleInterface')
for p in purple.PurpleGetConversations():
if purple.PurpleConversationGetName(p) == chat_name:
chat = p
chat_data = purple.PurpleConversationGetChatData(chat)
purple.PurpleConvChatSetTopic(chat_data, user, topic)
purple.PurpleConvChatWrite(chat_data, user, message, 0, int(time.time()))
I've written a small Socket.IO server, which works fine, I can connect to it, I can send/receive messages, so everything is working ok. Just the relevant part of the code is presented here:
var RedisStore = require('socket.io/lib/stores/redis');
const pub = redis.createClient('127.0.0.1', 6379);
const sub = redis.createClient('127.0.0.1', 6379);
const store = redis.createClient('127.0.0.1', 6379);
io.configure(function() {
io.set('store', new RedisStore({
redisPub : pub,
redisSub : sub,
redisClient : store
}));
});
io.sockets.on('connection', function(socket) {
socket.on('message', function(msg) {
pub.publish("lobby", msg);
});
/*
* Subscribe to the lobby and receive messages.
*/
var sub = redis.createClient('127.0.0.1', 6379);
sub.subscribe("lobby");
sub.on('message', function(channel, msg) {
socket.send(msg);
});
});
Here, I'm interested in the problem where certain client is subscribed to a different room, which is why I'm also using the sub Redis variable inside each socket connection: because each client can be subscribed to a different room and can receive messages from there. I'm not entirely sure whether the code above is ok, so please let me know if I need to do anything else than define the sub Redis connection inside the Socket.IO connection: this also means that a new Redis connection is spawned for each client connecting serving his messages from the subsribed room? I guess this is quite an overhead, so I would like to solve it anyway possible?
Thank you
Both node.js and redis are very good at handling lots of connections (thousands is no problem), so what you're doing is fine.
As a side note, you will want to look into upping your file descriptor limits if you do intend on supporting thousands of connections.