fspromises.writeFile() 在 process.exit() 上写入空文件
fspromises.writeFile() Writes Empty File on process.exit()
我找遍了,但我似乎无法找到退出时文件中什么也没有的答案。
对于上下文,我正在编写一个不和谐的机器人。机器人每小时存储一次数据。在商店之间的某个时候,我想存储数据以防我决定更新机器人。当我用命令手动存储数据,然后终止进程时,一切正常。现在,我希望能够终止进程而不必手动发送命令。因此,我有一个 SIGINT 处理程序,它以与我手动执行的方式相同的方式存储数据,并且在履行承诺后,我退出。由于某种原因,该过程结束后该文件不包含任何内容。这是代码(经过修剪)。
app.ts
function exit() {
client.users.fetch(OWNER)
.then(owner => owner.send('Rewards stored. Bot shutting down'))
.then(() => process.exit());
}
process.once('SIGINT', () => {
currencyService.storeRewards().then(exit);
});
process.once('exit', () => {
currencyService.storeRewards().then(exit);
});
currency.service.ts
private guildCurrencies: Map<string, Map<string, number>> = new Map<string, Map<string, number>>();
storeRewards(): Promise<void[]> {
const promises = new Array<Promise<void>>();
this.guildCurrencies.forEach((memberCurrencies, guildId) => {
promises.push(this.storageService.store(guildId, memberCurrencies));
})
return Promise.all(promises)
}
storage.service.ts
store(guild: string, currencies: Map<string, number>): Promise<void> {
return writeFile(`${this.storageLocation}/${guild}.json`, JSON.stringify([...currencies]))
.catch(err => {
console.error('could not store currencies', err);
})
}
因此,如您所见,当收到 SIGINT 时,我获得货币服务来存储其数据,该服务将公会映射到公会成员货币,即公会成员与其奖励的映射。它使用存储服务将数据存储在不同的文件中(每个公会都有自己的文件)。存储服务 returns 来自 writeFile 的承诺(当文件完成写入时应该是未定义的承诺)。货币服务累积所有承诺和 returns 一个在所有商店承诺都解决时解决的承诺。然后,在所有承诺都得到解决后,将向机器人所有者(我)发送一条消息,returns 一个承诺。在该承诺解决后,我们将退出流程。它应该是一个干净的出口,所有数据都已写入,机器人让我知道它正在关闭,但当我稍后读取文件时,它是空的。
我已经尝试在各种不同的地方登录,以确保以正确的顺序完成这些步骤,并且我没有收到奇怪的异步内容,而且一切似乎都在按预期进行,但我'我仍然得到一个空文件。我不确定发生了什么,非常感谢一些指导。
编辑:我还记得其他事情。作为另一个调试步骤,我尝试在货币服务 storeRewards() 承诺解决后读取文件,并且文件的内容有效*(它们包含有效数据,但它可能是旧数据,因为数据不经常更改) .因此,我的想法之一是 writeFile 的承诺在文件完全写入之前解决,但这在 the documentation.
中没有说明
编辑 2:答案是我写了两次。 post 或第一次编辑中显示的代码的 None 会清楚地表明我遇到了双写问题,因此我添加了导致问题的代码,以便未来的读者可以得到同样的结论。
感谢@leitning 在我的问题的评论中帮助找到答案。在文件名中写入一个随机的 UUID 后,我发现该文件被写入了两次。在问这个问题时,我曾假设我已经分享了所有相关信息,但我漏掉了一些东西。 process.once('exit', ...) 在调用 process.exit() (more details here) 之后被调用。退出事件的回调函数不处理异步调用。当回调函数returns时,进程退出。由于我在退出回调函数中复制了 SIGINT 回调函数中的逻辑,因此文件被第二次写入,进程在文件写入之前退出,导致文件为空。删除 process.once('exit', ...) 逻辑解决了这个问题。
我找遍了,但我似乎无法找到退出时文件中什么也没有的答案。
对于上下文,我正在编写一个不和谐的机器人。机器人每小时存储一次数据。在商店之间的某个时候,我想存储数据以防我决定更新机器人。当我用命令手动存储数据,然后终止进程时,一切正常。现在,我希望能够终止进程而不必手动发送命令。因此,我有一个 SIGINT 处理程序,它以与我手动执行的方式相同的方式存储数据,并且在履行承诺后,我退出。由于某种原因,该过程结束后该文件不包含任何内容。这是代码(经过修剪)。
app.ts
function exit() {
client.users.fetch(OWNER)
.then(owner => owner.send('Rewards stored. Bot shutting down'))
.then(() => process.exit());
}
process.once('SIGINT', () => {
currencyService.storeRewards().then(exit);
});
process.once('exit', () => {
currencyService.storeRewards().then(exit);
});
currency.service.ts
private guildCurrencies: Map<string, Map<string, number>> = new Map<string, Map<string, number>>();
storeRewards(): Promise<void[]> {
const promises = new Array<Promise<void>>();
this.guildCurrencies.forEach((memberCurrencies, guildId) => {
promises.push(this.storageService.store(guildId, memberCurrencies));
})
return Promise.all(promises)
}
storage.service.ts
store(guild: string, currencies: Map<string, number>): Promise<void> {
return writeFile(`${this.storageLocation}/${guild}.json`, JSON.stringify([...currencies]))
.catch(err => {
console.error('could not store currencies', err);
})
}
因此,如您所见,当收到 SIGINT 时,我获得货币服务来存储其数据,该服务将公会映射到公会成员货币,即公会成员与其奖励的映射。它使用存储服务将数据存储在不同的文件中(每个公会都有自己的文件)。存储服务 returns 来自 writeFile 的承诺(当文件完成写入时应该是未定义的承诺)。货币服务累积所有承诺和 returns 一个在所有商店承诺都解决时解决的承诺。然后,在所有承诺都得到解决后,将向机器人所有者(我)发送一条消息,returns 一个承诺。在该承诺解决后,我们将退出流程。它应该是一个干净的出口,所有数据都已写入,机器人让我知道它正在关闭,但当我稍后读取文件时,它是空的。
我已经尝试在各种不同的地方登录,以确保以正确的顺序完成这些步骤,并且我没有收到奇怪的异步内容,而且一切似乎都在按预期进行,但我'我仍然得到一个空文件。我不确定发生了什么,非常感谢一些指导。
编辑:我还记得其他事情。作为另一个调试步骤,我尝试在货币服务 storeRewards() 承诺解决后读取文件,并且文件的内容有效*(它们包含有效数据,但它可能是旧数据,因为数据不经常更改) .因此,我的想法之一是 writeFile 的承诺在文件完全写入之前解决,但这在 the documentation.
中没有说明编辑 2:答案是我写了两次。 post 或第一次编辑中显示的代码的 None 会清楚地表明我遇到了双写问题,因此我添加了导致问题的代码,以便未来的读者可以得到同样的结论。
感谢@leitning 在我的问题的评论中帮助找到答案。在文件名中写入一个随机的 UUID 后,我发现该文件被写入了两次。在问这个问题时,我曾假设我已经分享了所有相关信息,但我漏掉了一些东西。 process.once('exit', ...) 在调用 process.exit() (more details here) 之后被调用。退出事件的回调函数不处理异步调用。当回调函数returns时,进程退出。由于我在退出回调函数中复制了 SIGINT 回调函数中的逻辑,因此文件被第二次写入,进程在文件写入之前退出,导致文件为空。删除 process.once('exit', ...) 逻辑解决了这个问题。