1

我有一个重型节点应用程序,我正在使用 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. 更多时候,uidundefined。我的猜测是该文件尚未保存,因此当我尝试获取该文件时,它具有未定义的值。
  2. 即便如此if (uid == 'undefined')console.log(uid)还是丢了不少undefined。我不明白为什么,因为我正在“返回”。

代码真的就是这样。这if可能被称为每秒 15-20 次。没有其他代码可能会在控制台上抛出“未定义”,也没有任何写入数据库的代码。

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

编辑 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尚未完成写入的文件。

4

2 回答 2

2

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

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

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

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

我填了一个问题:

并发setItemgetItem可能导致无法处理does not look like a valid storage file

于 2018-10-01T10:59:36.343 回答
2

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

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

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

注释和取消注释选择存储到节点持久性或节点持久性周围的包装。

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)
})
于 2018-10-03T17:35:01.190 回答