1.3.4 not using modified class function node (in subflow?)

Using node-red 1.3.4, nodejs 14.17.0 I have a function node inside a subflow with a class definition embedded in the function node.

I find that if I edit the code inside the class and deploy (even a full deploy) the modifications are not seen, the class keeps using the old definition. I have to restart node-red to get it to use the new code. The code can be as simple as adding a node.warn() statement, even a syntax error is not seen. I don't yet know whether the fact that it is inside a subflow is significant. If I edit the code in the same node, outside of the class definition, then the modified code is seen (but mods inside the class already made are still not picked up).

I intend to generate a simple flow to exhibit the problem but thought I would post this first in case it is a known issue, to save me investigating further.

I can't replicate it with a simple class so this will take a bit more investigation.

Got it! It is nothing to do with being in a subflow, it is the fact that I am saving a class object in the context, and I can understand that keeping a class instance in the context may be problematic. This is the function:

class Test {
    warn() {
        node.warn("testing 2")
    }
}

if (!context.get("test")) {
    context.set("test", new Test())
}

test = context.get("test")
test.warn()
return msg;

Run it and then change the text output in the warn() call. A Deploy does not pick up the the modified text. Restarting node-red or clearing the context fixes it.

[{"id":"3faa08ce.24ca18","type":"function","z":"84405ff5.25fa6","name":"","func":"class Test {\n    warn() {\n        node.warn(\"testing 2\")\n    }\n}\n\nif (!context.get(\"test\")) {\n    context.set(\"test\", new Test())\n}\n\ntest = context.get(\"test\")\ntest.warn()\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":340,"y":1680,"wires":[[]]},{"id":"df7fa705.bd14d","type":"inject","z":"84405ff5.25fa6","name":"Test","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":190,"y":1680,"wires":[["3faa08ce.24ca18"]]}]

[Edit] I realise I had posted the wrong function and flow. Now corrected.

Maybe the solution is to use the on close function and do context.set("test", undefined)

Genius! Yes that does work around the problem.

So the question is, I suppose, does anything need to be done about it in node-red (if indeed there is a practical solution)?

I guess what you're asking is should a function nodes context be reset when the function node is (re)deployed?

It seems, from your example, it is not - I don't know if it should be. Perhaps Nick or Dave know if this is by design or incidental?

It wouldn't be quite such a genius workaround if I wanted to keep it in persistent context of course.

I think that is a different issue.

Not really. As you create the instance only when context is empty, changes to your class are not live until the context is deleted & a new instance is generated. I.e. until the context is cleared, the original code (instance) is held in memory. That's how js works.

So, to rephrase, if function context is supposed to be retained on a function redeploy, then your code is working exactly as expected/as written.

I don't think the code for a class is stored in the context, though I may be wrong. I imagine that what is happening is that the instance data includes some sort of reference to the class definition. When the function is re-deployed the new class definition is added to the code set but the original code is still present and the context data will still reference it. So perhaps there is a simple fix, that the original code needs to be linked to (or replaced by) the new one. That may not be simple, or even possible though, or I may have the mechanism wrong.

To clear the node context data on deploy is not a valid solution in the case that persistent context is in use, It would break the persistence.

Whether keeping a class object in persistent context even works I don't know .....

I have just realised that I posted the wrong function and flow earlier. Now corrected.

And the answer is, no it doesn't work. Amending the function to use file based context, running it and then restarting node-red results in "TypeError: test.warn is not a function". The only recovery path is to delete the context object. I guess the reason is that the class reference stored in context no longer refers to a valid class definition.

File context doesn't store functions Colin.

So the function node is kind of like a virtual machine, created when you deploy. the objects created in it from the class are kinda like their own living entity & kept alive so long as there is a reference to it. Even though you change the definition of the class, the instantiated object (held in context/memory) is still an instance of the original definition.

A class instance isn't a function, but I realise that you are right that class objects cannot be put in file context, it is only objects that can be stringified that can be put in file context. Even, for example, a Date object cannot be put in file based context with the expectation that it somehow automatically becomes a Date again when recovered.

I think that is down to the implementation. Each instance of the class object does not contain the code, but must contain some reference to the code. Whether it is possible (and practical) for the re-deploy code to account for this somehow I don't know. Quite possibly not.

I still maintain though that whether a function node should clear the node context on re-deploy is a separate, and much larger, issue. To clear the node context data on deploy would break the persistence for functions using file based node context.

That meant to refer to the fact classes are pretty much syntactic sugar to a function (under the hood) - not really the point here TBH.

ok, so I was being simplistic in my description - i did not mean to imply "Each instance of the class actually contains the code - the point i was trying to state was that the code that executes is the code that was instantiated regardless of changing the class definition because the object/function/instance is held/loaded into memory.

In the function code (server side) node.script.runInContext is called when fire a msg into it. At that point, the script is compiled. lets call this created instance V1. Then this V1 instance is stored in context/memory. When you modify and deploy a V2 of the class, node.script.runInContext is called again and the new version of the class is compiled however the V1 instance is still alive in memory because of context.

I think now that perhaps you are asking should the vm/sandbox be destroyed when you re-deploy? I dont think nodejs can do that (for technical reasons?).

I think you are likely right, in which case it may be that all that can be done is to include something in the documentation pointing out the potential issues with saving class objects in context.

1 Like

This topic was automatically closed 60 days after the last reply. New replies are no longer allowed.