Hello, I've built a dashboard page with uibuilder to display useful info.
A few bits of useful information, such as the list of US holidays, is almost 100% static so I'd like to cache it in node-red. What's the best way for node-red to determine the client browser has been refreshed or opened so I can push the cached information to it?
Have the browser request it after the page is loaded? Detect a control message from ui-builder?
There are various ways of caching and various controls for those ways. I think the first question though is whether you should bother at all? Would it make any material difference? How many client browsers will access the page and how many times will users connect/disconnect/reload? Unless it is a lot, I doubt you will ever see any realistic benefit from caching.
Having said that, the simplest cache for uibuilder is to use the uib-cache node. This caches data in Node-RED, not at the browser. Its purpose is to save Node-RED from having to make upstream queries every time someone accesses or reloads the page. It is a useful way of decoupling the data from the page(s). There is an example flow you can use to test that out.
If you really want to go beyond that, I'd need to know more about the source data, your flows and what kind of things you want to cache and for how long. There are certainly plenty more things we can do just from uibuilder though some caching is best done with a proxy service instead.
I've implemented a simple cache, but get this error in the browser when I try to update:
[uibuilderfe:checkConnect:setTimeout] Socket.IO reconnection attempt. Current delay: 2000
A timer driven flow saves the latest message into the global context.
When the uibuilder dashboard gets a "client connect" or "ready for content" message it sends the cached message if it exists.
When I invoke send() in node-red the browser gets nothing and throws a reconnection error.
I may not understand how SOCKET.io works. I can't just send a message to the browser?
Here's the cache fetch:
// Get in memory context
var homeMsgs = global.get('MsgCache') || {}
// Replay cache if requested
if (msg.hasOwnProperty('cacheControl') && msg.cacheControl === 'REPLAY') {
for (var topic in homeMsgs) {
var newMsg = homeMsgs[topic];
// Only send to a single client if we can
if (msg.hasOwnProperty('_socketId'))
{
node.warn("send to one: " + topic);
newMsg._socketId = msg._socketId;
node.send(newMsg);
}
else
{
node.warn("send to all: " + topic);
node.send(newMsg);
}
}
}
return null;
As you can see, uibuider's cache makes use of Node-RED's context stores. So you can have a cache that survives a Node-RED restart if you like, simply by changing the Node-RED settings to allow for a file or redis based store.
The documentation doesn't specify if this cache saves the page structure, the page content, or both.
Given the projects thrust toward dynamic structure I suspect it's both.
My page isn't dynamic so I don't need or want the page structure to be cached.
So for a VueJS based setup, you are doing your UI in the front-end and you would use the cache for the raw data. For a zero-/low-code approach, you would probably cache the _ui data.
But, as always with uibuilder, the choice is yours.
Yup, that's fine, you will cache the latest data you need for loading into the VueJS managed data variables.
If anyone is interested the issue with this code is that node.send() is an asynchronous send.
It appears you must also call another function to notify the library the message is complete and it may be sent. If you take too long the underlying connection times out.