Summary:
I have a chat functionality in my Node.js
app and want to send messages to the clients via socket.io. I trigger the emit to the client via PubSub. Now, when running the PubSub Subscription everything works (i.e. prints out messages) in roughly 70% of the cases, but would sometimes just stop and not do anything (in particular it would also not print out an error).
I can confirm that the missing 30% (messages) are being published to the topic though, as a different subscription to the same topic receives the messages.
Any help with debugging this would be highly appreciated.
Details
This is my Stack:
- Node.js
- socket.io
- express.js
- passport.js
- MongoDB
- react.js
Process:
- Anna sends a message in chat (this writes to the database and also publishes to PubSub topic "messages")
- Node.js express app runs a subscription and would then based on the message content emit to whoever else should receive the message.
- BoB who is on the same channel as Anna would, in this case, receive the message.
Why do I not directly emit from Anna to Bob? The reason being that I want to have an AppEngine in between the messages and potentially add some logic there, this seemed a good way doing it.
Subscription
const pubSubClient = require('./client');
const errorHandler = function(error) {
console.error(`ERROR: ${error}`);
throw error;
};
module.exports = listenForMessages =(subscriptionName="messageReceiver",io) => {
const subscription = pubSubClient.subscription(subscriptionName);
// Listen for new messages until timeout is hit
subscription.on("message", (message) => {
console.log(`Received message ${message.id}:`);
const parsedMessage = JSON.parse(message.data)
parsedMessage._id = message.id
console.log(parsedMessage)
if (parsedMessage.to === "admin") {
io.to(`admin:${parsedMessage.from}`).emit("NewMessage", parsedMessage);
} else {
io.to(`${parsedMessage.to}`).emit("NewMessage", parsedMessage);
}
message.ack();
});
subscription.on('error', errorHandler);
}
Server.js
...
const listenForMessages = require("./message_processing/listen");
listenForMessages("messageReceiver", io);
Sample console output
The following console output was generated by running the app locally with two browsers [one in incognito] chatting with each other. It can be seen that only the very last message was actually picked up by the listener (and printed out). Funnily enough, due to the async nature of the calls, the printout of the received message came before the log that the message was sent (i.e. latency surely can't be a problem here).
[0] went into deserialize user
[0] Message 875007020424601 published.
[0] went into deserialize user
[0] Message 875006704834317 published.
[0] went into deserialize user
[0] Message 875006583857400 published.
[0] went into deserialize user
[0] Message 875006520104287 published.
[0] went into deserialize user
[0] Message 875006699141463 published.
[0] went into deserialize user
[0] Received message 875006881073134:
[0] {
[0] from: '5e949f73aeed81beefaf6daa',
[0] to: 'admin',
[0] content: 'i6',
[0] seenByUser: true,
[0] type: 'message',
[0] createdByUser: true,
[0] createdAt: '2020-04-20T07:44:54.280Z',
[0] _id: '875006881073134'
[0] }
[0] Message 875006881073134 published.
In some other cases, earlier messages work and then the listener seems to stop.