-
Notifications
You must be signed in to change notification settings - Fork 51
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Server-side State Management #61
Comments
Thanks Bart, this is certainly something we're trying to take into account. Architecturally, I've already made accounts for this, although not fully implemented yet. Thanks for the feedback. |
Server-side state now in place from all widgets, apart from Chart, which is different due to requiring more than just the latest |
Hi @joepavitt, |
No formal API, although you could connect to the SocketIO connection and jump on the existing events we use: https://flowforge.github.io/flowforge-nr-dashboard/contributing/guides/events.html#widget-change As a first pass, I constrained the focus such that if you refresh the browser, then browser-state is restored (as it's also stored server-side) |
For custom UI nodes, currently we just expose a There is however a plan to add extensions for We could also look at adding |
@joepavitt, Currently my ui-svg node has a number of different input messages that can be injected into the node, and as a result the client-side DOM of all connected clients are updated. When you want to do this in Flexdash, it works completely different:
Currently the server-side API (from 2) was rather limited, but convenience methods could be added later on (e.g. to delete an item from an array at index i, ...). I assume that there are functions that developers can call in dashboard 2.0 to update their server-side state? |
Thanks for the clarification. Currently we aren't able to support additional custom widgets at the moment, but it is in the pipeline. When we do this work, then we would also flesh out easier function calls to make integration smoother than it currently is. |
I had interpetred your use of the "custom nodes", as using |
We are also open to source integrations if you would like to include ui-svg as a core part of Dashboard 2.0 |
@joepavitt,
BTW your collegua @Steve-Mcl was my partner in crime at the time being to develop the ui-svg node ;-) So summarized this Github issue is about a server-side state that can be managed via an API (like in Flexdash), and the API functions take care of sending the delta to the clients (instead of just replaying the last msg): Note that I don't know anything about Vue.js, so my picture might perhaps be not entirely correct... So - unless you don't like the idea of such an API - I would appreciate if you could reopen this issue, so I can keep track of the status in the future. Thanks for your understanding! |
Hi @joepavitt, |
You may have to explain it a little too me. We have two separate events:
Up to each widget how to handle these |
@joepavitt |
Continuing another discussion here, since it is related to the above proposal. It was a confusion I had about the message queue in the notification node, but to generalize the discussion a bit I will use e.g. the ui-led node. Current setup - msg queue
These messages are stored in a queue, and the last message from that queue is being binded to the Vue template. That works fine but has some disadvantages:
We had a lot of similar troubles at the time being in the old dashboard. Especially for the ui-svg node users it was quite a hell, because an SVG drawing contains LOT's of state stuff: e.g. a floorplan with blinking sensors, and so on... Users created all kinds of workarounds in their flows (to solve the partial state supplied by the last replayed msg), but there was unfortunately no decent solution. For example they queued the last N messages and replayed these N messages after a refresh or when a new client connects. But how do you determine the value of N:
Flexdash setup - server side stateThorsten had found a clever (and yet rather simple) solution for this problem in Flexdash: So we have the same sequence of messages as in the first screenshot. But on the server side, these messages will be used to update the server side state (which contains all the LED properties).
The state sync between server and client is the responsibility of the dashboard, not the individual ui nodes. Imho such a setup is much easier to understand for ui node developers, and dashboard contributors. But it becomes now harder to refactor the current queue mechanism, because everything (core ui nodes, third party ui nodes, ....) heavily depend on the current mechanism. That is the reason why I started this discussion at the initial development phase of dashboard D2... Thanks for reading :-) |
I am confused by your description, as the method I have used in the gauge-classic node is more like the flexdash approach than the one you describe. I have a similar problem, in that for a multi-needle gauge, the messages for the needle values come in independently, identified by topic. Also there is other dynamic state data that arrives via other messages. In the js file I join the data from individual messages so that the server always has a full set of state data. The needle values are in an array |
Hi @colinl,
Anyway perhaps it is all clear to everybody else. But I don't see the trees through the forest anymore after a long day at work. I only see a bunch of messages, each of them containing only a part of the state. And that it is a lot of puzzling to extract the full state from all those messages. Thorstens model seems to be much more clear to me. And most of the boilerplate code would be inside the dashboard, not inside the individual nodes.... |
Sorry @colinl, |
I think I see a much better paradigm to use. I have been too hung up on the concept of messages coming in from node red and the messages going to the client. In fact I don't think they have to be directly related at all. At the moment, considering just one of the properties that may come via a message, I have in the initialisation section
This should also work, and is much cleaner. In initialisation
and in
At the moment I can't see any reason that would not work. I will give it a try. |
Well it nearly works, apart from what I thing is a bug. Perhaps @joepavitt can comment on this. If, in
then actually it sends the original incoming message to the clients, not the contents of storedData. If I refresh the page then it does send storedData. I seems that
still sent the original message. The only way I could get it to work was by copying the data across to the original message
Should I submit an issue Joe, or am I trying to do something silly? |
@colinl,
Indeed that is the whole point of Thorsten's mechanism. The node receives input messages, and updates the server-side state. That state is then send to the clients, NOT the message itself! The clients don't know the concept of messages at all. They just receive an update of their state. You almost implemented Thorsten's idea, with a couple of disadvantages:
That way the entire message storage/sending/handling could be ditched. Because if it is decided to stick to that, we know from experience (i.e. old dashboard) that we will end up this way:
Hopefully I don't offend anybody, because that is not my intention. But I am very worried where we will end up in the end if we continue using messages to the clients, because I have been there before unfortunately. And it is very understandable that people fall into the message based approach trap, because the message sending and replaying seems VERY logical in a Node-RED context. But it is nothing but trouble for the dashboard. Personally I would love to see a poc in a branch with e.g. the Notification node, to see if we can get a clean codebase that does the job. I am more than happy to help with this with some help from you and Joe, of course if Joe sees the benefits of it... Hopefully @joepavitt has some time to follow this discussion... |
I agree entirely that the current interface could be much improved, for all the reasons you describe. I would have thought that additional methods could be added to the existing interface to make things easier, without breaking existing nodes. I would be happy to help where I can with that, even if only by being a sounding board and testing stuff. I haven't looked at all about how to send data back from the client into node red. I am looking at developing such a node, so I will be looking at that soon. |
BTW the reason why I would like to do a POC with the Notification node, is because that node requires support for a lot of different use cases:
|
Good question. There are only a few ui nodes yet, so I am pretty sure that we could ask them to do it another way. For template nodes I don't know. Never used those, so not sure if they make use of message queues. Because that would indeed be a pitty.
Just to explain that a bit more. Currently you send a message to the clients to hide or show the notification. Which caused me some troubles last week, because my control message was stored in the queue. And since it had become that way the last message, my notification title was suddenly gone (because that title was not part of my last message). Instead of sending such control messages to the clients, you would set a
Ah, that might be a party stopper. Not sure at the moment how to handle that. Because if you have one shared state on the server, there is no difference for one specific client. Suppose you want to show the notification on a single client, then the |
Is the |
I don't have the time anymore to read all the issues, so now talking from my ancient experience... When a message is injected into the ui node:
So it looks like this boils down to something like this:
I 'think' that such a setup is pretty understandable for users and ui developers. Does this make sense, or have I overlooked something? |
Seems mostly reasonable to me, though I am not familiar with the way msg._client works at the moment.
How would the framework know which properties were of interest? Also the data in the message might not map directly to properties. For example, in my gauge node, needle values are passed in with the value in payload and the needle identifier in the topic. That needs to be processed to update the
Might the client side need to know what properties were updated? There may be some pre-processing that needs to be done, or do you think that should be entirely handled by the vue binding. At the moment in the gauge node I do some pre-processing, but perhaps I can avoid that. I have realised that I think I can improve the technique I have used with the existing framework to avoid sending the whole state object every time. I need to code it to see if there is a flaw in the idea though. |
It does work, and seems obvious now, as most things do once you see how. The key is that the full data store is sent to the clients on refresh. So in the client that can be processed and saved locally. When a new message is received in the .js file it will generally only contain a subset of properties. Those can be used to update the data store (subject to msg._client if necessary) and then passed on with just that subset to the clients. The clients can then pick up any properties in the message and update accordingly. So now in the .js file initiallisation section I have
And in
In fact it is only the last line that has changed, so that it sends the message on the clients, not the full data store. I didn't have to change the client code at all as it already only picked up properties present in the message it was given (which is the full set in the case of a refresh and a subset in the case of a later message). The same code processes the incoming message whether it is the initial full set or just a subset. I think that is effectively what you have in your flowchart. |
Absolutely correct. I should have added that on my diagram, but now indeed it looks like the input message is being parsed automatically, which is not the case. Consider it done...
Again correct. I had only added the bindings on my diagram, but indeed you should be able to handle client side state changes programmatically. I have added that also to the diagram now...
Ah really. I wasn't aware that it already worked that way. Because I have been seeing last msg replaying. So I had the impression that only that last msg was available, not the full state...
So you always store the values in the datastore. Even when the msg has a I still believe it is useful that the framework should do all of this automatically behind an API, so ui node developers just can do their thing (without having to learn how everything works behind the scenes). Thorsten also had some other cool ideas for this. Suppose a notification needs to be visible for 60 seconds.
An API allows all ui nodes to do it the same way... |
Appreciate this is a long thread, and I need to catch up properly, but quick note to say that Dashboard internals handle everything re: Third party nodes don't have to do anything themselves |
Client side store means we have a centralised place all the data is stored across the app, without a need to keep checking in on the state from the server-side.
|
https://dashboard.flowfuse.com/contributing/guides/state-management.html Is the best docs I have for detailing the different stores, the server-side API, and it's purpose |
I don't see how that can be the case. What will I see in my |
OK, but in my widget, what use is it to me? |
You have access to the whole |
It's a best practice to store your incoming By having it centralised, it means we have a single source of truth on the client-side, not having the data distributed to each node. |
Ah, having done some experiments I see that the |
I don't understand what that means in practice but again will start a forum thread. It is separate to the discussions here I think. |
Hi everybody,
Really nice to hear that Flowforge is supporting the developments of a new dashboard. Thanks for that!!
Developing ui nodes for the old dashboard was rather time consuming, partly due to the msg replay mechanism. Because only the last message is being replayed, but the state of a ui node is most of the time constructed incrementally by a sequence of multiple input messages. Which required a lot of time to get always the correct state on the client side. And for every ui node, you had to solve similar issues...
Thorsten made an entirely different implementation with Flexdash. The state is stored on the server side, which can be manipulated with an API. All delta changes will be send to all existing clients. So the entire state on the client side is always up to date, and clients can update their ui when a delta arrives. And when a new client connects, it automatically gets the entire state. Which imho is much easier to work with, if well designed of course.
So hopefully some ideas from e.g. Flexdash are being taken into consideration...
Good luck with this nice project!!!
Bart
The text was updated successfully, but these errors were encountered: