Durable and reliable contextStorage - DB/mysql/mariadb based

If I remember correctly, the context file storage writes a new file with a temporary name then renames the old file and the new one, or something along those lines, so the window for failure is very small.

FYI! I am running into a very basic issue with Redis. :frowning:

Created a ticket separately to avoid cluttering with a different discussion in this...

Unfortunately, they don't...they write to the same file hence all this issues. Unless it is resolved in a later versions.

I decided to write a custom context storge that will suport different databases. I currently have redis working now I'll look into sql dbs.

@jakonnode what will you be using, sqlite, postgre, mysql?

1 Like

I am sure I checked the code at one point. How do you know it is writing to the same file?

I am checking redis with persistence but it is running into some issues. If I can't make it work I will use MariaDB/MySQL.

Thanks ziga. Otherwise I plan to write one.

JAK

Looking at the code that appears to be incorrect. node-red/packages/node_modules/@node-red/runtime/lib/storage/localfilesystem/util.js at master Ā· node-red/node-red Ā· GitHub

You're right Colin. Even the old version has rename from a tmpFile to contextFile. I wonder how come it gets corrupt with such atomic operation.

It is easily reproducible when the power to the device goes and it reboots. It is not reproducible when we kill node-red though.


async function writeFileAtomic(storagePath, content) {
    // To protect against file corruption, write to a tmp file first and then
    // rename to the destination file
    let finalFile = storagePath + ".json";
    let tmpFile = finalFile + "."+Date.now()+".tmp";
    await fs.outputFile(tmpFile, content, "utf8");
    return fs.rename(tmpFile,finalFile);
}

Atlast, I found a way to deal with this problem of contextFile getting corrupt and the node-red is unable to restart itself.

After evaluating redis context module, realized that all the global.get & context.get will have to be modified as they respond in async manner hence it can't be default contextStore. Same will be the case if we come up with database based contextStore too. Since they are an external service, it is only best to do get as async.

The solution I came up with is that I wrote a javascript function that will find the context file corresponding to the node that writes to the context, checks for likely corruption of the context file. If found corrupt, it traverses through the file and remove the last/corrupt array element.

This jsscript is called before invocation of node red so that it takes care of any possible corrupt file before starting in the node-red.service file.

ExecStartPre=/usr/bin/env node /usr/local/bin/fix-node-red-context-file.js
ExecStart=/usr/bin/env node-red-pi $NODE_OPTIONS $NODE_RED_OPTIONS

Hope this approach works fine. Thanks everyone for prompting me on possible solution(s)

feel free to also attach the fixup file as an example for others :slight_smile:

Here are couple of context storage plugins for Node RED: GitHub - sebenik/node-red-context

Atm there's support for Redis, MySSQL/MariaDB, PostgreSQL and SQLite.