WCF Data Service Operation loses order of subEntities in Silverlight Client - sorting

I have a WCF DataService operation, which exposes Businesses and Customers.
On the server side, I sort each Business's Customers by LastName, this way:
List<Customers> orderedCustomers = business.Customers.OrderBy(c=> c.LastName).ToList<Customers>()
business.Customers.Clear()
foreach (Customers customer in orderedCustomers )
business.Customers.Add(customer )
And on the client side (asynchronously, in Silverlight), I expand each business's customers like this:
Context.BeginExecute<Business>(new Uri(serviceurl + BeginGetAllBusinessData&$expand=Cutomers, UriKind.Relative), GettingBusinessDataCompleted, Context);
My issue is: The customers in businesses are not sorted on the client side (they are sorted server-side). It happens the same with any field I choose for the OrderBy. Looks like serialization chooses its own order. I'd like to sort them on the server side.
Am I missing something???

Are you sure the returned List is out of order? If your GettingBusinessDataCompleted callback is responsible for adding the expanded content to the UI then things can appear out of sequence.
Asynchronous operations are not guaranteed to complete in the order they were begun.

Related

Cache emitted value for dependent observable but not source observable

I am currently implementing a new feature at work. The app wants to give sellers an admin where they can see various things. An example of one of the things they can see on their dashboard is their last 10 orders.
The order's API only returns an array of various ids (customer id, product id, seller id, etc) In order to populate the orders page, I have to make 3 different API call on each order to get the data to render on the order list page
Now that I have to create a dashboard that is different from the order list page, I do not want to make such a tedious API call again. I want to create a dashboard$ observable that has the last emitted value of orderList$ but I do not want anything subscribed to orderList$ to be cached.
So when orderList$ is called, it gets the lastest orderList data from the server (I do not feel something as sensitive as order list should be cached), when dashboard$ is called, get the last emitted value of orderList$ and if orderList$ has not emitted any values then dashboard$ can make a request to retrieve order list.
When working with a reactive state of mind, I like to define what should happen based on events. By this I mean that I'll have a Subject in which in can push values into to notify an event and from there we can react to these events.
In your case, here's an idea for what you want:
const navigationToOrdersPage$$ = new Subject<void>();
const refreshOrdersButtonClicked$$ = new Subject<void>();
const orders$: Order[] = merge(
navigationToOrdersPage$$,
refreshOrdersButtonClicked$$
).pipe(
switchMap(() => yourOrderService.getOrders()),
shareReplay({
bufferSize: 1,
// make sure that even if we don't have anyone subscribed to that observable
// we keep the result in the cache and if we ever go to the orders page or click
// on the refresh button it'll be updated anyway but with this it's safe to navigate
// to another page than orders and the dashboard and if you go back to the dashboard
// you'd still get an instant result
refCount: false,
})
);
So here it'd be safe to reuse this observable on both the admin and the dashboard page. Of course, you'll need to call next on the 2 subjects when appropriate so that the orders can be refreshed when they need to.

Best practice for subscribe and publish architecture for chat-like app

I'd like to know what best practices exist around subscribing to changes and publishing them to the user. This is a pretty broad and vaguely worded question. Therefore, allow me to elaborate on this using an example.
Imagine the following (simplified) chat-like application:
The user opens the app and sees the home screen.
On this home screen a list of chat-groups is fetched and displayed.
Each chat-group has a list of users (members).
The user can view this list of members.
Each user/member has at least a first name available.
The user can change its name in the settings.
And now the important part: When this name is changed, every user that is viewing the list of members, should see the name change in real-time.
My question concerns the very last point.
Let's create some very naive pseudo-code to simulate such a thing.
The client should at least subscribe to something. So we could write something like this:
subscribeToEvent("userChanged")
The backend should on its part, publish to this event with the right data. So something like this:
publishDataForEvent("userChanged", { userId: "9", name: "newname" } )
Of course there is a problem with this code. The subscribed user now gets all events for every user. Instead it should only receive events for users it is interested in (namely the list of members it is currently viewing).
Now that is the issue I want to know more about. I could think of a few solutions:
Method 1
The client subscribes to the event, and sends with it, the id of the group he is currently viewing. Like so for example:
subscribeToEvent("userChanged", { groupId: "abc" })
Consequently, on the backend, when a user changes its name, the following should happen:
Fetch all group ids of the user
Send out the event using those group ids
Something like this:
publishDataForEvent("userChanged", { userId: "9", name: "newname" }, { groupIds: ["abc", "def" })
Since the user is subscribed to a group with id "abc" and the backend publishes to several groups, including "abc", the user will receive the event.
A drawback of this method is that the backend should always fetch all group ids of the user that is being changed.
Method 2
Same as method 1. But instead of using groupIds, we will use userIds.
subscribeToEvent("userChanged", { myUserId: "1" })
Consequently, on the backend, when a user changes its name, the following should happen:
Fetch all the user ids that relate to the user (so e.g. friendIds based on the users he shares a group with)
Send out the event using those friendIds
Something like this:
publishDataForEvent("userChanged", { userId: "xyz", name: "newname" }, { friendIds: ["1", "2" })
An advantage of this is that the subscription can be somewhat more easily reused. Ergo the user does not need to start a separate subscription for each group he opens, since he is using his own userId instead of the groupId.
Drawback of this method is that it (like with method 1 but probably even worse) potentially requires a lot of ids to publish the event to.
Method 3
This one is just a little different.
In this method the client subscribes on multiple ids.
An example:
On the client side the application gathers all users that are relevant to the current user. For example, that can be done by gathering all the user ids of the currently viewed group.
subscribeToEvent("userChanged", { friendIds: ["9", "10"] })
At the backend the publish method can be fairly simple like so:
publishDataForEvent("userChanged", { userId: "9", name: "newname" }, { userId: "9" } )
Since the client is subscribed to user with userId "9", amongst several users, the client will receive this event.
Advantage of this method is that the backend publish method can be held fairly simple.
Drawback of this is that the client needs quite some logic to subscribe to the right users.
I hope that the examples made the question more clear. I have the feeling I am missing something here. Like, major chat-app companies, can't be doing it one of these ways right? I'd love to hear your opinion about this.
On a side note, I am using graphql as a backend. But I think this question is general enough to not let that play a role.
The user can change its name in the settings.
And now the important part: When this name is changed, every user that is viewing the list of members, should see the name change in real-time.
I assume the user can change his name via a FORM. The contents of that form will be send with a HTTP-Reuqest to a backand script that will do the change in a DB like
update <table> set field=? where userid=?
Preferred
This would be the point where that backend script would connect to your web socket server and send a message like.
{ opcode:'broadcast', task:'namechange', newname='otto' ,userid='47111' }
The server will the broadcast to all connected clients
{task:'namechange', newname='otto' ,userid='4711' }
All clients that have a relationship to userid='4711' can now take action.
Alternative 1
If you cant connect your backend script to the web socket server the client might send { opcode:'broadcast', task:'namechange', newname='otto' ,userid='47111' }
right before the FORM is trasnmitted to the backend script.
This is shaky because if anything goes wrong in the backend, the false message is already delivered, or the client might die before the message goes out, then no one will notice the change.

Axon - Cannot emit query update in different microservice

I'm bothering with situation when I want to emit query update via queryUpdateEmitter but in different module (microservice). I have application built upon microservices and both are connected to the same Axon Server. First service creates subscriptionQuery, and sends some commands. After a while (through few commands and events) second service handles some event, and emits update for firstly subscribed query. Unfortunately it seems like this emit doesn't get to subscriber. Queries are exactly the same and sits in the same packages.
Subscription:
#GetMapping("/refresh")
public Mono<MovieDTO> refreshMovies() {
commandGateway.send(
new CreateRefreshMoviesCommand(UUID.randomUUID().toString()));
SubscriptionQueryResult<MovieDTO, MovieDTO> refreshedMoviesSubscription =
queryGateway.subscriptionQuery(
new GetRefreshedMoviesQuery(),
ResponseTypes.instanceOf(MovieDTO.class),
ResponseTypes.instanceOf(MovieDTO.class)
);
return refreshedMoviesSubscription.updates().next();
}
Emitter:
#EventHandler
public void handle(DataRefreshedEvent event) {
log.info("[event-handler] Handling {}, movieId={}",
event.getClass().getSimpleName(),
event.getMovieId());
queryUpdateEmitter.emit(GetRefreshedMoviesQuery.class, query -> true,
Arrays.asList(
MovieDTO.builder().aggregateId("as").build(),
MovieDTO.builder().aggregateId("be").build()));
}
This situation is even possible in the newest version of Axon? Similar configuration but within one service is working as expected.
#Edit
I have found a workardound for this situation:
Second service instead of emitting query via queryUpdateEmitter, publishes event with list of movies
First service handles this event and then emits update via queryUpdateEmitter
But still I'd like to know if there is a way to do this using queries only, because it seems natural to me (commandGateways/eventGateways works as expected, queryUpdateEmitter is the exception).
This follows from the implementation of the QueryUpdateEmitter (regardless of using Axon Server yes/no).
The QueryUpdateEmitter stores a set of update handlers, referencing the issued subscription queries. It however only maintains the issued subscription queries handled by the given JVM (as the QueryUpdateEmitter implementation is not distributed).
It's intent is to be paired in the component (typically a Query Model "projector") which answers queries about a given model, updates the model and emits those updates.
Hence, placing the QueryUpdateEmitter operations in a different (micro)service as where the query is handled will not work.

How to architecture a web-socket server with client subscription of specific responses in Phoenix?

I'm developing a web-socket server that I need to send real-time messages using Phoenix Framework to my clients.
The basic idea of my web-socket server is that a client can subscribe for some type of information and expect to receive only it, other clients would never receive it unless they subscribe to it too, the same information is broadcasted to every (and only) client subscribed to it in real-time.
Also, these information are separated in categories and sub categories, going down to 4 levels of categories.
So, for example, let's say I have 2 types of category information CatA, and CatB, each category can have sub categories, so CatA can have CatA.SubCatA and CatA.SubCatB sub categories, each sub categories can also have other subcategories and so on.
These information are generated by services, one for each root category (they handle all the information for the subcategories too), so we have CatAService and CatBService. These services needs to run as the server starts, always generating new information and broadcasting it to anyone that is subscribed to it.
Now, I have clients that will try to subscribe to these information, my solution for now is to have a channel for each information type available, so a client can join a channel to receive information of the channel's type.
For that I have something like that in the js code:
let channel = socket.channel("CatA:SubCatA:SubSubCatA", {})
channel.join()
channel.on("new_info", (payload) => { ... }
In this case, I would have a channel that all clients interested in SubSubCatA from SubCatA from CatA can join and a service for CatA that would generate and broadcast the information for all it's sub categories and so on.
I'm not sure if I was able to explain exactly what I want, but if something is not clear, please tell me what so I can better explain it, also, I made this (very bad) image as an example of how all the communication would happen https://ibb.co/fANKPb .
Also, note that I could only have one channel for each category and broadcast all the subcategories information for everyone that joined that category channel, but I'm very concerned about performance and network bandwidth, So my objective is to only send the information to only the clients that requested it.
Doing some tests here, it seems that If the client joins the channel as shown in the js code above, I can do this:
MyServerWeb.Endpoint.broadcast "CatA:SubCatA:SubSubCatA", "new_info", message
and that client (and all the other clients listening to that channel, but only then) will receive that message.
So, my question is divided in two parts, one is more generic and is what are the correct ways to achieve what I described above.
The second is if the solution I already came up is a good way to solve this since I'm not sure if the length of the string "CatA:SubCatA:SubSubCatA" creates an overhead when the server parses it or if there is some other limitation that I'm not aware.
Thanks!
You have to make separate channels for each class of clients and depending upon the ids which you are getting, you can broadcast the messages after checking about the clients joining the channel
def join("groups:" <> group_slug, _params, socket) do
%{team_id: team_id, current_user: user} = socket.assigns
case Repo.get_by(Group, slug: group_slug, team_id: team_id) do
nil ->
{:error, %{message: "group not found"}}
group ->
case GroupAuthorization.can_view?(group.id, user.id) do
true ->
messages = MessageQueries.group_latest_messages(group.id, user)
json = MessageView.render("index.json", %{messages: messages})
send self(), :after_join
{:ok, %{messages: json}, assign(socket, :group, group)}
false ->
{:error, %{message: "unauthorized"}}
end
end
end
This is an example of sending messages only to the users in groups which are subscribed and joined to the group. Hope this helps.

Joining same room more then once and clients in a room

I'm trying to figure out what happens if the clients emits to join the same room more then once, To test and find answer on this I wanted initially to find out how many clients room has after same clients send more then one emit for joining the room, but Rooms chapter in wiki https://github.com/Automattic/socket.io/wiki/Rooms is outdated. When I try to use "io.sockets.clients('room')" I get error "Object # has no method 'clients'".
So I got two questions:
1. what happens if client tries to join same room more then once? Will he get emits for that room for each time he has tried to join?
2. How can I find out which clients are in a room?
Im using socket.io v1.0.2
I got an answer on this question at socket.io github.
As per this line of code, the socket will receive emits only once. The socket is added to a room only once, and if another attempt is made for the same socket to join the room, this attempt will be ignored.
There is currently no public API for getting the clients, and there is some discussion ongoing in #1428. If you really need to get them, for some reason, you can fetch the actual clients from the adapter, assuming you are not using the redis adapter like so:
socket.join('test room');
var clients = io.sockets.adapter.rooms['test room'];
console.log(clients);
for (var clientId in clients) {
console.log(io.sockets.connected[clientId]);
}
Fixed getting clients in a room at socket.io ~1.4.5 like this:
socket.join('test room');
var room = io.sockets.adapter.rooms['test room'];
console.log(room);
for (var socketId in room.sockets) {
console.log(io.sockets.connected[socketId]);
}
Its working fine and does not gives any error,it ignores the second request for joining the room from that socket which is already in the room.
I have actually tried and implemented a solution where
when user click on message notification it joins that specific room from which the notification came and, and when he sends very first message he again join that specific room (It is because I have build a Chat-Directive in AngularJS).
Client Side
1) User Open Notification
Socket.emit('JoinRoomWithThsID', notification.ConversationID);
2) user Sends First Message in that room
Socket.emit('patientChatRoomMessage', adminmessage);

Resources