A guide to understanding 'Persistent Context'

#7

Also, it's certainly possible to write persistent context to a non-wearable media like a network hard drive or something ?

#8

Great write up. I have one question however. When I wish to check on the stored value (file store) the directories under 'context' use obscure node numbering. Would it be possible to use the tab name, (or node name) which is what one might expect to look under? Just a thought. I only care when I'm coding because that's when I'm checking to see things are doing what I expected. But I have to say, I do love the persistent context. Have done a lot of rewriting to incorporate it but the previous solutions I created were not 1,000% reliable and certainly not as elegant as this.
ST

#9

The file store isn't really intended for the user to access directly - its an internal implementation detail. The naming is based on the id of the nodes and flows as they are guaranteed to be unique and don't change. Node names can be changed by the user and you can have many nodes named the same thing.

#10

yes, that's what I meant in my reply where I said:

use some external storage mechanism (USB hard drive, cloud storage api...).

1 Like
#11

OK, I understand. Thank you.

BTW, I think I read it's not on the list for development however, just for some feedback, I would vote in support of being able to create a utility function somewhere that I can globally call upon in any flow / node rather than repeat code in many function nodes. (NOTE: creating a custom / private NR node for this would be overkill and I think less elegant). I have succeeded in achieving this by assigning a function to a context.global variable (NR complains when it starts) but I read this is not recommended and that it may be policed one day. I took it out when I read that because I didn't want to have to go back deep into all my code at some future date when I forgot all the tiny little details should the ability to do this change. Just so you know .... some input from the cheap seats.

#13

Cool!

But were do i place this?

contextStorage: 
	storeName    : { module: "storeModule" }
}

When i put it in the end before the last } i get an error on starting node-red.

Do i understand well that when i put this in settings.js that the global are persistent?

#14

It’s not that it will be policed. Most storage mechanisms only really support serialisable objects, and functions aren’t serialisable. So now we do have persistable context, depending on the storage mechanism, functions (and circular objects) won’t be stored.

#15

Solved! There was an { missing after contextStorage:

#16

'storeName' and 'storeModule' are the place holder names. Did you look at the examples?

#17

As @zenofmud mentions, he's raised a pull-request to get this integrated into our proper documentation - I'm keen we have good docs that can be linked to for these sorts of questions, rather than rely on linking to forum posts.

The pull-request is here: https://github.com/node-red/node-red.github.io/pull/86

Please take a look at the proposed changes and provide any feedback on the PR - and also marvel at how easy it is to contribute to the documentation... :wink:

2 Likes
#18

agree, but i really dont understand how to do that, but instead of doing nothing i post it here in the hope it helps some one...

It's all ready difficult enough for me to get it working :wink:
Because when i stop start NR now the global.get is still empty

#19

@RogierQ - your right, the opening '{' was missing - fixed now.

1 Like
#20

What is not clear to me now, is when it is saved

Doing some tests the results of saved global dont show up directly in the json file
Or is it saved when deploying?

@zenofmud thanks!

#21

It may help if you share exactly what you have put in your settings file and show us how you then set a value in context - just so we can check you're doing it right.

#22

Don’t forget, the current implementation only gets flushed to disk every 30secs. It is there if you “get” it immediately( from the cache) but may not be in the file.

1 Like
#23

@RogierQ, Here's a test I made:

contextStorage: {
    store: {
        module:"localfilesystem"
    },
    default: {
        module:"memory"
    }
},

Here's how my test flow looks:

Here's the code:

[{"id":"1b12c10.509463f","type":"tab","label":"Persistent Context Test","disabled":false,"info":""},{"id":"73e93758.9aa008","type":"inject","z":"1b12c10.509463f","name":"","topic":"","payload":"B","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":130,"y":140,"wires":[["532bf815.546508"]]},{"id":"7d06f012.51671","type":"inject","z":"1b12c10.509463f","name":"","topic":"","payload":"A","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":130,"y":100,"wires":[["532bf815.546508"]]},{"id":"5d36a28e.6f402c","type":"inject","z":"1b12c10.509463f","name":"","topic":"","payload":"C","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":130,"y":180,"wires":[["532bf815.546508"]]},{"id":"532bf815.546508","type":"function","z":"1b12c10.509463f","name":"Set context","func":"flow.set(\"cxTest\", msg.payload, \"store\");\nreturn msg;","outputs":1,"noerr":0,"x":470,"y":140,"wires":[["4fb35e5c.8cb35"]]},{"id":"4fb35e5c.8cb35","type":"debug","z":"1b12c10.509463f","name":"Set value","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","x":660,"y":140,"wires":[]},{"id":"667f1611.ddc8a8","type":"inject","z":"1b12c10.509463f","name":"Show stored context","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":170,"y":240,"wires":[["fce453bf.1b35a"]]},{"id":"fce453bf.1b35a","type":"function","z":"1b12c10.509463f","name":"Get context","func":"msg.payload = flow.get(\"cxTest\",\"store\") || \"empty\";\nreturn msg;","outputs":1,"noerr":0,"x":470,"y":240,"wires":[["5663ce9f.ca75b"]]},{"id":"5663ce9f.ca75b","type":"debug","z":"1b12c10.509463f","name":"Get value","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","x":660,"y":240,"wires":[]},{"id":"cecdc7e2.8718e8","type":"inject","z":"1b12c10.509463f","name":"Get stored context at deploy/startup","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":true,"onceDelay":"1","x":220,"y":280,"wires":[["fce453bf.1b35a"]]}]

1 Like
#24

(did you start and end the flow with three backtic's on the line before and after it? I could not import it)

And??? I had to fudge to get your flow to import, but it is working for me. Are you saying that you have an issue? If so what is it?

#25

@zenofmud, sorry, I was replying to @RogierQ to help show a test flow. Fixed the code as well. Thanks.

#26

Is this configurable? There's no denying that this is essential behavior on SD but there are bound to be folks running NR on way bigger hardware. (For example 4 of my deployments are in ESX clusters with flash based SAN storage...)

#27

Yes, that's why I said it was the default mode.

The documentation describes the various configuration options for the file store.

https://nodered.org/docs/api/context/store/localfilesystem