Show "Active Node" and errors in template based web front-end

I'm using node-red as a back-end and simple front-end for a report, which pulls data from various sources and populates a Word document using docx-template, ready for editing/publishing to our customers.

The front-end is based on a template node which defines HTML for a form, which posts to a http node to initiate the report, using a _blank target. The report returns on completion, again using a template node, to set HTML for the _blank target with a link to download the report. This works fine, but there is no feedback to the user if the flow fails, or anything to confirm that it is still running.

I can do a catch node which will let me print whatever error occurs, rather than returning the download page - but I want to go further and show the path of the message through each node, with any errors printed inline. Ideally populating a div on the form in real-ish time so the user can watch the progress of the request.

Wracking my brains for a way to do this - was thinking of trying to use AJAX to monitor a /progress endpoint, which is written to whenever the report is running - but this would not handle multiple sessions/simultaneous reports. Websockets is another option - but we would presumably have the same issue with sessions.

Are we aware of any ways to achieve this using the msg or some sort of session context?

Thanks in advance.

Add properties to the msg (e.g. msg.before and msg.after). Before each node in the path, set msg.after with the value of msg.before then set msg.before with the name or description of the next operation.

When an error is caught, you can determine from these 2 values where in the process you got to.

This assumes you don't have any nodes that ditch the original message (new comers often create new messages in function nodes - you should always try to update the incoming msg and return that)

Using msg properties (instead of context) will avoid the issue of using context and concurrent async operations interfering with the values (since they belong to their own msg AKA PURE)

How long does it take between initiating the flow and delivering the report? How many messages do you want to show during this time?

You could send progress messages something like this

If there is a delay of 5 seconds at any stage, the trigger will send an error message.
Payload of "Finished" resets the trigger

Thanks both - yes - sticking with msg properties makes sense to keep it in the right context.

My main issue is how to return the information to the web front end, without interfering with the one-to-one HTTP request -> HTTP response. If I could do incremental http responses to the initial HTTP request, that would be ideal - but that won't work - HTTP response ends the flow and the msg context is lost. I haven't used the trigger node before to send messages - would that help in this case? How would I get the data back to the client?

A quick solution could be to:

CLIENT SIDE

  1. Generate a UUID and send it with the initial request.

SERVER SIDE
2. Upon first initiation of the flow, grab the uuid and store it in the msg object
3. Use Link-Call to call to a function that updates flow context lookup object to update the before and after states before each node
4. Add a 2nd endpoint /status/:uuid. This can be called independently. It will look up the uuid parameter in the flow context and return the current state of that operation

CLIENT SIDE
5. do an ajax request/async fetch to grab the status from /status/:uuid

State Store

For the state context, I would probably make this an object with createdAt and lastAccessed time stamps so that you can clear up the flow status on a schedule

e.g.

subroutine for updating state

link-in -> function -> link-out (return)

function


const RouteStates = flow.get('RouteStates') || {}
const routeState = RouteStates[msg.uuid] || {
    createdAt: new Date(),
    accessedAt: null
}

 // update states
routeState.before = msg.before
routeState.after = msg.after
routeState.updatedAt = new Date()

// update flow context
RouteStates[msg.uuid] = routeState
flow.set('RouteStates', RouteStates)

State Access via /status/:uuid

http-in "/status/:uuid" -> function -> http-response

function

const uuid = msg.request.params.uuid
const RouteStates = flow.get('RouteStates') || {}
const routeState = RouteStates[uuid] || {
    createdAt: new Date()
}

// update flow context
routeState.accessedAt = new Date()
RouteStates[msg.uuid] = routeState
flow.set('RouteStates', RouteStates)

// return state
msg.payload = routeState
return msg

100% untested, straight off the top of my head. will likely need refinement and/or a rejig but hopefully it unblocks you.

Nice! Thanks, I'll give this a go.