feat(data): 命令行导入导出通道 + 修上传解析的句柄泄漏
- scripts/data-transfer.js:tables / export / import --preview|--apply,与网页版共用同一套内核。 用于 nginx/CDN 挡住 1.22MB 上传时的备用通道,也可挂 cron 做异地备份。 - readBundle:校验失败中途抛错时关闭 readStream 与 readline,避免反复上传坏包耗尽文件句柄。 - docs:补命令行用法与体积限制说明。
This commit is contained in:
@@ -217,6 +217,22 @@ function openMaybeGzip(filePath) {
|
||||
return fs.createReadStream(filePath).pipe(isGzip ? zlib.createGunzip() : new (require('stream').PassThrough)())
|
||||
}
|
||||
|
||||
/**
|
||||
* 逐行吐出,并在**任何**退出路径上关掉底层流。
|
||||
*
|
||||
* 校验失败时 readBundle 会中途抛错,如果不在这里兜住,文件句柄就跟着异常一起漏掉 ——
|
||||
* 服务器上反复上传坏包会把 fd 耗光(排查起来极难,因为错误信息只有「数据包损坏」)。
|
||||
* 包在外层 for-await 里的生成器,在 break / throw / 正常结束三种情况下都会走到 finally。
|
||||
*/
|
||||
async function* linesOf(reader, input) {
|
||||
try {
|
||||
for await (const line of reader) yield line
|
||||
} finally {
|
||||
try { reader.close() } catch { /* 已经关了 */ }
|
||||
try { input.destroy() } catch { /* 已经释放 */ }
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取并校验数据包。
|
||||
*
|
||||
@@ -241,7 +257,7 @@ async function readBundle(filePath) {
|
||||
const counts = new Map()
|
||||
let lineNo = 0
|
||||
|
||||
for await (const raw of reader) {
|
||||
for await (const raw of linesOf(reader, input)) {
|
||||
const line = raw.trim()
|
||||
if (!line) continue
|
||||
lineNo++
|
||||
|
||||
Reference in New Issue
Block a user