Persistent Storage of Global Context

Hi,
Windows 10 - NR 0.20.7
I have been trying to use persistent storage to allow continuation over a restart. I have set the contextStorage to 'localfilesystem'. I can see the files as described in the documentation so I assumed all was well until I lost some global context items as follows:

I defined an object to be stored in global context (global.set("xxxx")) which consists of a set of methods and a data array associated storing the status of various devices. The methods allow access to the array, greatly simplifying and standardising updates etc.

stats1 = {
	getname : function() {
	    var addr = arguments[0];
		var name = "Not Known";
		for (var devnum in this.devices) {
			if (addr == this.devices[devnum].address) {
				name = this.devices[devnum].name;
			}
		}
		return name;
	},
	setname : function() {
	    var addr = arguments[0];
		var name = arguments[1];
		for (var devnum in this.devices) {
			if (addr == this.devices[devnum].address) {
				this.devices[devnum].name = name;
				return devnum;
			}
		}
		return -1;
	},
	getaddr : function() {
	    var name = arguments[0];
		var addr = "Not Known";
		for (var devnum in this.devices) {
			if (name == this.devices[devnum].name) {
				addr = this.devices[devnum].address;
			}
		}
		return addr;
	},
	setaddr : function() {
	    var name = arguments[0];
		var addr = "Not Known";
		for (var devnum in this.devices) {
			if (name == this.devices[devnum].name) {
				this.devices[devnum].address = addr;
			}
		}
		return addr;
	},
	setvisible : function() {
	    var addr = arguments[0];
		var what = arguments[1];
		for (var devnum in this.devices) {
			if (addr == this.devices[devnum].address) {
				this.devices[devnum].visible = what;
			}
		}
		return addr;
	},
	add : function() {
	    var addr = arguments[0];
	    var dev = {};
	    var date = new Date();
        dev.address = addr;
        dev.name = "Device" + (this.devices.length);
        dev.value = "Not Set";
        dev.date = this.formatDate(date);
        dev.time = this.formatTime(date);
        dev.visible = false;
		this.devices.push(dev);      // add to array
		return this.devices.length;
	},
	exists : function() {
	    var addr = arguments[0];
		for (var devnum in this.devices) {
			if (addr.toUpperCase() === this.devices[devnum].address.toUpperCase()) {
				return devnum;
			}
		}
		return -1;
	},
	updateValue : function() {
	    var date = new Date();
	    var addr = arguments[0];
		var what = arguments[1];
		var exists = this.exists(addr);
		if (exists !== -1) {
			if (what.toLowerCase() !== "silent") this.devices[exists].value = what;
            this.devices[exists].date = this.formatDate(date);
            this.devices[exists].time = this.formatTime(date);
		}
		return exists;
	},
    formatDate : function(date) {
        var d = date,
            month = '' + (d.getMonth() + 1),
            day = '' + d.getDate(),
            year = d.getFullYear();
    
        if (month.length < 2) month = '0' + month;
        if (day.length < 2) day = '0' + day;
    
        return [day, month, year].join('/');
    },
    formatTime : function (date) {
        hours = '' + date.getHours();
        if (hours.length < 2) hours = "0" + hours;
        minutes = '' + date.getMinutes();
        if (minutes.length < 2) minutes = "0" + minutes;
        seconds = '' + date.getSeconds();
        if (seconds.length < 2) seconds = "0" + seconds;
        return [hours, minutes, seconds].join(':'); 
    },
	devices : []
};

Anything stored within the 'devices' array is persisted, the methods are not!

Am I breaking some rules I don't know about or should this work?

Regards

Context can only persist JSON encodable data. You cannot persist javascript code.

Thanks for the prompt reply.

I'll think of something else.

Rgds

You might want to think about this the other way around. Assuming you want those functions to be available to multiple function nodes, you can define them in settings.js (in the globals section) and then reference them in your function nodes.

To make things more sustainable and manageable, you can also move the function definitions to your own module and then use require statements in settings.js.

1 Like

Thanks @TotallyInformation.

I have never considered that. It’s been useful in development to be able to modify the functions ‘on the fly’ and just save them in the one object. Re-deploying and re-saving then makes them available immediately without the need to restart.

As a current workaround, at restart Check for the existence of one of the functions, if it’s not there I re-instate all of them and clone the restored data to recreate the ‘object’. A bit dodgy on restart timing, but it hasn’t failed so far.

Rgds

Agreed, you could put them into a single module file without an issue then you can use a "proper" code editor like VScode as well which is nice.

However, you are correct that it can be annoying if you have to restart a lot during development. On my dev machine, Node-RED is started manually via nodemon or PM2 with watches in place so it auto-restarts when certain files like settings.js and external modules change. Helps a little.

You could put it on the first tab with an inject set to go off upon Node-RED startup that creates the object. The first tab always executes first.

Then, once the functions stabilise, move them to a module.

Ok.
Tried a few things.
Still not really getting there though.
I really wanted to encapsulate the code as part of the object, and I haven't been able to tie this together.

I hasten to add that none of this is a show-stopper, but has become something of a challenge .I would like to resolve over time ...

Currently it is parked. I have a system which works, and it is not being constantly restarted so I can live with minor start up quirks (though honestly I haven't had them yet!).

Thanks for responding.

Regards