I am creating a real-time notifications feature within my app that will use Pusher to automatically notify the user when they get a notification (which is created by certain actions taken by users they follow).
I know how to set up the event and have it broadcast, but I'm confused as to the channels to broadcast these notifications on. The situation will be user A follows many other users, but also has many followers himself.
If user A posts new content, we can trigger an event that broadcasts a notification to all of his followers that he just posted something. The question here is, do we broadcast this channel on "user.A"? That means every other user that follows user A will have to subscribe to that channel all the time along with the channels of every other user they follow.
So, what's more efficient, to dynamically broadcast across possibly hundreds of different channels (each channel representing one of user A's followers) OR should each user automatically listen to the channels of possibly hundreds of different users?
Not sure which is more efficient. Thanks!
Related
I was wondering what should be the granularity of the topic names in an event-driven service-oriented architecture.
Let's imagine we have a user management system where users can perform different actions like signing up, signing in, modifying some profile attributes, etc. If we wanted to notify the rest of the services of these changes, I can think of some possibilities for the topic naming:
One topic per each of the classic CRUD operations in each of the models (excluding read since the state of the user does not change). We would have user-created, user-updated, user-deleted. This approach is generic enough, but there would be potentially many services subscribed to user-updated topic and discarding all those events that do not modify a specific field.
One topic per business-relevant change. In addition to user-created and user-deleted, we could have events like user-email-updated, user-signed-in (which otherwise would be fired as a user-updated event where the date of the last sign-in was changed), etc. My feeling is that even though it would be handy for those subscribers only interested in a very specific change, it would be harder for those services that need to sync whatever happens to the user, as they would have to be subscribed to an increasing number of topics to keep track of all the changes in the user model.
A mix between 1 and 3, where both events user-updated and user-email-updated would be sent when the user updates the email, but just user-updated would be sent if the user changes the profile.
The way to go is to implement the 2nd option but implement it with a topic hierarchy to allow subscribers to choose the granularity of their interest (as in subscribing to users.* or *.updated or user.actions.login etc. )
Some technologies (e.g. RabbitMQ) has this capability built-in, for others you can implement a topic registry and provide the infrastructure to manage subscriptions yourself
i am trying to use the API to get the total number of messages posted by each user during a certain period. Ideally, I would be able to break the number of messages by the type of channel (public, private, direct messages.) Is this possible? I am looking through the API documentation but haven't found anything. I would be using it to create a script that would automatically generate weekly activity reports.
Thank you for any advice you can provide!
There is no special endpoint for this information as far as I know, but you can generate something similar yourself by looping though all channels and counting the message per user, e.g.
Get list of all channels with conversations.list
Get history of each channel with conversations.history
Count messages per user
Of course your results would not include message from channels, that your bot has no access too (e.g. some private channels, direct message channels).
I want to implement websocket-based push notifications in a website. I already serached here on SO and on google, but my question is a bit different.
My use-case:
when userB replies to a comment posted by userA, userA will receive a push notification with a link to the article/comment (It is similar to SO)
My research:
on the web, people seem to agree that (in terms of scalability) it is better to limit the total amount of websocket channels. That leads to 1 channel per every user (= each channel will only contain 1 user). Why? Think about a group chat where 1 user could participate in 10 or more discussions --> that would mean 10 or more channels per user.
So, 1 channel per user is the best solution (until now).
I plan on using this bundle https://github.com/GeniusesOfSymfony/WebSocketBundle
In the docs, there is a page about How to Send a message to a specific user https://github.com/GeniusesOfSymfony/WebSocketBundle/blob/master/Resources/docs/SessionSetup.md . This method allows you to send a message ONLY to 1 user between all the users that are subscribed to the same channel. You do this by passing the user's username to the function.
This opens a new possiblity: creating only 1 big channel with all the logged in users subscribed to it INSTEAD of creating N channels where N is the number of authenticated users.
In other words, which is better: 1 channel with 1000 subscribers or 1000 channels with 1 subscriber?
I suggest you use a publish/subscribe framework and rely on the implementation of that framework to scale. You seem to be solving a problem that has been solved many times before. Search for ActiveMQ publish/subscribe, Kaazing JMS, Kaazing AMQP, Pusher, IBM MQTT/WS, etc.
I have a schema that looks something like:
Installation <user, etc>
User <id, contact info, etc>
activities <fromUser, toUser, type[follow, like, share]>
...
I want to occasionally fire off a push notification to someone's followers. I can get the follows for someone like so:
var followsQuery = new Parse.Query("activity");
followsQuery.equalTo("toUser", user.id);
followsQuery.equalTo("type", "follow");
.. and iterate through the follows and call Parse.Push.send for each of them, but I don't think this is the best way to go about doing this, and I'm worried about this timing out for people with large number of followers.
How do I form the pushQuery so as to form a join with the user and activities tables?
You can create a channel for each user called "follow_[objectId]" where [objectId] is that user's objectId. Whenever a user follows someone, add that someone's follow channel to the user's push channels. Then, whenever you want to send a push notification to someone's followers, just push to their follow channel. Their followers should be subscribed to that channel and get the push.
This can be problematic if a user follows many people. When they login, the app would have to query for all the people they follow, and subscribe to all those channels, which could take a while.
Imagine I have a User model and also a Message model. User has many messages.
Then in the client I do a:
io.socket.get('/user/2/messages'....
I get all my user messages and there is no problem trying to get someones else messages because I have a policy for that. Good.
I want to listen if the user has new messages, if I do a:
io.socket.on('message')
I get every message created, mine or not mine.
So: Can I listen just for MY messages? AKA listen for associated messages but not all of them.
Maybe using a policy or something for just that. Because even if there is a way to listen to them, anyone can modify the client to listen to what he wants to, I need to filter all of that.
Yes, you can. The trick is to listen for user events with the "addedTo" verb, rather than listening directly for message creation. The code would be something like:
io.socket.on('user', function(msg) {
if (msg.verb == 'addedTo' && msg.attribute == 'messages') {
// A new message was added to the user's "messages" collection
var messageId = msg.addedId
// From here you can request /message/[messageId] to get the
// message details if you need them
}
});
More info on the .publishAdd() doc page.
Note that only the ID of the added message is given; you may find you want the whole thing. You can handle that by either making a separate request for the new message, or overriding publishAdd as is suggested in this answer.
The only catch here is to make sure you're limiting who gets subscribed to those user events. It sounds like you have a policy in place that prevents users from accessing /user/:id/messages for other users. You'll want want preventing them from accessing /user/:id for other users as well (at least via sockets), since they will be subscribed to any user they access that way.
If this is undesirable--that is, if you'd like people to be able to hit those routes--then an alternative would be to use the autoSubscribe model property to restrict the automatic subscription that blueprints normally do. autoSubscribe is normally set to true, which means that any time a socket request is made for a model, the requesting socket will be subscribed to all events for that model instance. You can instead set it to an array of contexts that should be subscribed to. Contexts are specific events you're interested in, like update or destroy (more about contexts in the docs). Finally, you can set autoSubscribe to false to restrict subscription to that model entirely. Then you can just subscribe manually with .subscribe() whenever you want to listen for events.
You can see some examples of contexts and autoSubscribe in action in the sailsChat sample app.