Node-persist on heavy Node.js app not returning values

Node-persist on heavy Node.js app not returning values

我有一个重节点应用程序,我正在使用 node-persist 将数据保存到本地数据库。

在特定步骤中,我有这个:

const localdb = require('node-persist')
const storage = localdb.create({ttl: true})
await storage.init()

function game(socket, log, opts) {

   // [...]

    async function scoreHandler(data) {
        if (data.scoreUp) {
            await storage.setItem(data.sid,data.uid)
        } else if (data.scoreDown) {
            try {
                let uid = await storage.getItem(data.sid);

                if (typeof uid == 'undefined') {
                    return;
                }

                console.log(uid);
            } catch (e) {
                return;
            }
        }
    }
}

这段代码在长函数中有点深。一切都很简单。但是有两个问题:

  1. uid 通常是 undefined。我的猜测是该文件尚未保存,因此当我尝试对其进行 getItem 时,它具有未定义的值。
  2. 即使 if (uid == 'undefined')console.log(uid) 仍然会抛出许多 undefined。我不明白为什么,因为我是 "returning".

代码就是这样。这个if大概每秒调用15-20次。没有其他代码可能会在控制台上抛出 "undefined",也没有任何写入数据库的代码。

为什么会这样?我该怎么做才能妥善处理它?

编辑 1

第2点我明白了。我忘了放 typeof.

编辑 2

我按要求添加了 init

如果我删除 try...catch,我经常会收到此错误:

(node:9608) UnhandledPromiseRejectionWarning: Error: [node-persist][readFile] ... does not look like a valid storage file!
    at fs.readFile (...node-persist/src/local-storage.js:277:66)
    at FSReqWrap.readFileAfterClose [as oncomplete] (fs.js:511:3)

所以,我的猜测是 getItem 正在尝试读取 setItem 尚未完成写入的文件。

似乎node-persist 处理并发读写不可靠。

如果在执行 setItem 时调用 getItem,则会抛出此错误。

唯一的解决方案是,这由库修复,或者您确保在 setItem.

时永远不会调用 getItem

我的建议是将与该存储相关的所有内容打包到一个自己的 class 中。这样您以后就可以轻松地用另一个库替换它。

我填了一个issue:

Concurrent setItem and getItem can lead into an unahdled does not look like a valid storage file

再补充一点@t.niese 所说的内容,库基本上没有提供并发性。解决方案之一是序列化对库的调用。下面是序列化对库的所有调用的代码示例。

另外,给定的库将每个键值对写入一个文件。我认为序列化每个键的调用会提供更好的吞吐量。

说了这么多,这应该是在图书馆处理的。

注释和取消注释选择存储到 node-persist 或围绕 node-persist 的包装器。

const localdb = require('node-persist')
const when = require('when');


class QueuedStorage  {

  constructor() {
    this.storage = localdb.create({ ttl: true, logging: false})
  }

  async init() {
    await this.storage.init();
  }


  async getItem(key) {
    this.current = when(this.current,
            () => { return this.storage.getItem(key)},
            () => { return this.storage.getItem(key)});
    return this.current;
  }

  async setItem(key, value)  {
    this.current = when(this.current,
            () => { return this.storage.setItem(key,value)},
            () => { return this.storage.setItem(key,value)});
    return this.current;
  }
};


//const storage  = new QueuedStorage();
const storage = localdb.create({ ttl: true, logging: true })


async function main () {
  await storage.init()

  try {
    const key = 'DSF-AS-558-DDDF';
    const fs = new Array(10000)
      .fill(0)
      .map((e,i) => function() {
        if(i%2) return storage.getItem(key)
        else return storage.setItem(key,i)}());

    Promise.all(fs).then(values => console.log(values));

   } catch (err) {
     console.error(err)
   }
}

main().catch(err => {
  console.error(err)
})