We currently evaluating solutions for implementing server-sent events (not neccecarily using the Server-Sent Events EventSource Transport).
Our use case is actually quite similar to Stackoverflow. We've got a custom CMS implemented as SPA that supports collaborative editing. As first step we want the server inform all clients on the same page when another user has modified it.
The obvious choice would be chosing SignalR for this but this statement on XSockets's comparison page got me thinking:
If a framework broadcasts data to all clients connected we have just
inverted the AJAX issue and now we have a server hammering clients
with information they do not want.
Is this still true with SignalR 2? I mean wouldn't broadcasting to all clients regardless of group membership make groups totally useless in the first place?
Some Stats:
> 10000 active users
> 10000 pages
A message sent to a group in signalr will only arrive at the clients in that group. So there is no need to worry about broadcasting if you use groups.
Groups are smart until you you have to do something like #Lars Höppner describes, groups are not dynamic and they are really just a very simple subscription. It is just like having pub/sub where you say that you are subscribing to a topic "A" but in SignalR you are a member of a group "A" instead.
If you do not use groups signalr will broadcast, that can be ok but consider this.
You have 2 pages "A" and "B", they both connect to the Hub "MyHub".
When you send a message to all clients from "MyHub" to the method "MyMessage" and only the page "A" has implemented a client-side method for "MyMessage" the clients on page "B" will still get that message sent to the browser if you look in the frames tab (in chrome)
So messages will arrive at clients not interested in the message, not a big deal until you get a lot of clients or send sensitive data.
If you never connect to the same hub from 2 different pages you will be fine. And if you always use groups you will also be fine. Otherwise you will have to think about where the messages will arrive!
Of topic:
- My favorite thing about signalr is the nice transports!
- The worst thing about signalr is that they have transports due to the fact that they have desgined it thinking that websockets is a OS feature (win8 2012 server to get websockets)
When you send messages to a group, the clients that aren't in the group don't receive the message. This is based on a pub/sub model on the server (so when you use groups, it's not the client that decides whether it's interested in the message), so there is no "hammering all clients" going on in that case.
I think what the XSockets team is talking about in this paragraph is that with XSockets, you have more fine-grained control over who to send messages to. So instead of sending to a group with a specific name (which you have to create first), you can send to clients with certain properties (sort of like a dynamic group):
But what happens if you want to send to all clients within the range
of x km from y? Or if you want to target only males between 25 - 30
yrs that has red hair
You'd have to write your own code to do that in SignalR. This could, for example, be done on top of the code that maps users to connections. A simple solution (not necessarily the best) could use LINQ to select the appropriate users depending on the properties you're interested in, then get all corresponding connection ids from the ConnectionMapping instance to send to.
In SignalR you can subscribe to a topic (group) and get messages only for the topics you are subscribed, and global messages.
Working with groups.
I am not completely sure about what that paragraph want to mean.
Related
I am using SignalR in my web api to provide real-time functionality to my client apps (mobile and web). Everything works ok but there is something that worries me a bit:
The clients get updated when different things happen in the backend. For example, when one of the clients does a CRUD operation on a resource that will be notified by SignalR. But, what happens when something happens on the client, let's say the mobile app, and the device data connection is dropped?.
It could happen that another client has done any action over a resource and when SignalR broadcasts the message it doesn't arrive to that client. So, that client will have an old view sate.
As I have read, it seems that there's no way to know if a meesage has been sent and received ok by all the clients. So, beside checking the network state and doing a full reload of the resource list when this happens is there any way to be sure message synchronization has been accomplished correctly on all the clients?
As you've suggested, ASP NET Core SignalR places the responsibility on the application for managing message buffering if that's required.
If an eventually consistent view is an issue (because order of operations is important, for example) and the full reload proves to be an expensive operation, you could manage some persistent queue of message events as far back as it makes sense to do so (until a full reload would be preferable) and take a page from message buses and event sourcing, with an onus on the client in a "dumb broker/smart consumer"-style approach.
It's not an exact match of your case, but credit where credit is due, there's a well thought out example of handling queuing up SignalR events here: https://stackoverflow.com/a/56984518/13374279 You'd have to adapt that some and give a numerical order to the queued events.
The initial state load and any subsequent events could have an aggregate version attached to them; at any time that the client receives an event from SignalR, it can compare its currently known state against what was received and determine whether it has missed events, be it from a disconnection or a delay in the hub connection starting up after the initial fetch; if the client's version is out of date and within the depth of your queue, you can issue a request to the server to replay the events out to that connection to bring the client back up to sync.
Some reading into immediate consistency vs eventual consistency may be helpful to come up with a plan. Hope this helps!
I'm using Node.js and ws for my WebSocket servers and want to know the best practice methods of tracking connections and incoming and outgoing messages with Azure Azure Application Insights.
It appears as though this service is really only designed for HTTP requests and responses so would I be fine if I tracked everything as an event? I'm currently passing the JSON.parse'd connection message values.
What to do here really depends on the semantics of your websocket operations. You will have to track these manually since the Application Insights SDK can't infer the semantics to map to Request/Dependency/Event/Trace the same way it can for HTTP. The method names in the API do indeed make this unclear for non-HTTP, but it becomes clearer if you map the methods to the telemetry schema generated and what those item types actually represent.
If you would consider a receiving a socket message to be semantically beginning an "operation" that would trigger dependencies in your code, you should use trackRequest to record this information. This will populate the information in the most useful way for you to take advantage of the UI in the Azure Portal (eg. response time analysis in the Performance blade or failure rate analysis in the Failures blade). Because this request isn't HTTP, you'll have to mend your data to fit the schema a bit. An example:
client.trackRequest({name:"WS Event (low cardinality name)", url:"WS Event (high cardinality name)", duration:309, resultCode:200, success:true});
In this example, use the name field to describe that items that share this name are related and should be grouped in the UI. Use the url field as information that more completely describes the operation (like GET parameters would in HTTP). For example, name might be "SendInstantMessage" and url might be "SendInstantMessage/user:Bob".
In the same way, if you consider sending a socket message to be request for information from your app, and has meaningful impact how your "operation" acts, you should use trackDependency to record this information. Much like above, doing this will populate the data in most useful way to take advantage of the Portal UI (Application Map in this case would then be able to show you % of failed Websocket calls)
If you find you're using websockets in a way that doesn't really fit into these, tracking as an event as you are now would be the correct use of the API.
People recommend to use signalR groups, when multiple clients are interested in same kind of message. I am bit curious, how this concept internally works. Why sending message through SignalR group to multiple clients are faster than sending it to individually client?
You can refer to the below link for details on how SignalR works -
http://www.asp.net/signalr/overview/getting-started/real-time-web-applications-with-signalr
I am not sure there is a noticeable enough performance difference, there is more coding involved in being able to send to an individual, because you should to get their connectionId and code for that extra layer of code, rather than just dumping them into their own group, and broadcasting to that group even if it only contains a single client.
In many of the examples I've seen, such as the StockTicker app, it's assumed that all clients would be interested in the updates to all stock prices...
I'm trying to determine a best practice for when a client only cares about a subset of updates...
Would I:
broadcast all updates to all clients, and let the clients determine
"if they care" in the client method?
register with each client connection the "items of
interest" and maintain a client connection table somewhere,
broadcasting iteratively to all clients which have expressed that
interest?
Create a SignalR Group for every stock (for example), and
register clients to each particular stock-group "of interest" and
broadcast only to a particular group during an update of the related
stock?
something else I'm missing...
In an effort to make this question less subjective, what are the pitfalls of each of the above scenarios (rather than "which do you like better?")?
Thanks gang.
"Would I:"
"broadcast all updates to all clients, and let the clients determine "if they care" in the client method?"
This solution is probably the simplest to implement and reason about. Unfortunately, this solution also creates the most network traffic. It also may be considered insecure in some scenarios where the messages being sent are sensitive and should be hidden from some clients.
"register with each client connection the "items of interest" and maintain a client connection table somewhere, broadcasting iteratively to all clients which have expressed that interest?"
This seems fairly similar to SignalR groups in concept, but broadcast iteratively to individual clients typically isn't as efficient as broadcasting to a group. This is primarily because SignalR only has to publish one message to its bus per group broadcast.
Still, you might want to maintain a "client connection table" containing the "items of interest" for each client even if you end up using the built-in SignalR groups functionality. SignalR only allows you to add/remove clients to/from a group and broadcast to a group, so if you want to find out who's currently in a group you are going to have to track that yourself.
If you do maintain your own table, you can avoid sending messages you know no client is currently interested in. You could also automatically resubscribe clients to their items of interest when they leave and come back.
"Create a SignalR Group for every stock (for example), and register clients to each particular stock-group "of interest" and broadcast only to a particular group during an update of the related stock?"
This would be my choice. Groups align naturally to "items of interest". Given your scenario, I don't see much of a downside, particularly if you also maintain your own "client connection table" as well.
"something else I'm missing..."
I think you covered the three basic options.
I'm working on an application that allows users to send internal message to one-another.
I'll tell you what the current setup is and please help me figure out how to make it work or perhaps suggest another angle to take. We're using BlazeDS with Spring.
User A listens for messages on
message topic Chat.A
User B listens for messages on message topic Chat.B
Both users listen for global messages (system-wide messages) on topic Chat.System
So we have a multi-topic consumer for the personal message topic and one for the global message topic.
So a couple of questions I have:
Is it better to do it as two
distinct consumers (that share the
same handler function) or as one,
multi-topic consumer?
How do I check that the client A is actually the one listening to Chat.A and not just some one else that knows how to write BlazeDS clients? We have Spring Security in place, but how can I listen for subscription requests and block them if their user name (pulled from security context) doesn't match the sub-topic that they requested?
I've also read about selectors. Well, that looked promising, but again, how do I check that when a consumer uses selector="for == A || for == System that the consumer belongs to a client that has authenticated as that "for" user.
How do selectors compare/contrast to sub-topics? What's the best situation for each of them?
A selector is basically an expression you can use to filter which messages will be dispatched through your consumer. According to the docs, it uses SQL 92 conditional expression syntax:
http://livedocs.adobe.com/blazeds/1/blazeds_devguide/help.html?content=messaging_6.html
A subtopic is sort of a special case of a selector, filtering out messages whose "DSSubtopic" header don't match the provided value.
The important thing to understand with both of these is that the client determines which messages are sent to it, and as such it cannot be relied upon entirely for security.
To implement secure server-based filtering of messages based on an authenticated user's identity, see my answer to a related question here:
Flex Messaging Security
As far as multiple Consumers vs. MultiTopicConsumer, not sure there. They're both going to use the same underlying ChannelSet, so it ought not to have a big performance difference. I think it's mostly a question of whether it's convenient to have one event handler that responds to all messages from the MultiTopicConsumer or whether it's easier to have separate event handlers for each Consumer.
I usually use subtopics for this. But if you do it that way make sure that you disable subscriptions to wildcard subtopics.