Firebase 工具:使用大 JSON 文件设置数据库时如何避免 "out of memory" 错误?如何通过 firebase-tools 流式传输 JSON?
Firebase Tools: How to avoid "out of memory" errors when setting database with a big JSON file? How to stream JSON via firebase-tools?
我们有一个 GitHub 操作,使用 firebase-tools
将数据从一个 Firebase 项目复制到另一个项目(我们使用的是最新版本,9.11.0
) package:
firebase use fromProject && firebase database:get / -o export.json
firebase use toProject && firebase database:set -y / export.json
这在我们的数据变大之前一直运行良好,现在我们收到以下错误:
FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - JavaScript heap out of memory
作为临时修复,我们也可以应用节点 --max-old-space-size
标志,这只会增加节点进程可用的内存:
node --max-old-space-size=4096 /home/runner/work/foo/foo/node_modules/firebase database:set -y / export.json
考虑到我们的数据会不断增长,我们想实施一个适当的修复,在我的理解中是通过 streaming 和 JSON 来设置数据。但是,我不确定 firebase-tools
是否允许这样做。搜索 Github 个问题没有找到任何有用的信息。
也许除了流式传输之外,还有另一种有用的方法可以在设置之前将巨大的 JSON 文件分成块?
谢谢!
我们使用 Firebase HTTP 的 HTTP 流 API 来克服保存、本地修改和上传巨大(超过 256mb)JSON 文件的麻烦。
我们构建了一个函数,用于将数据流从一个项目的数据库传输到另一个项目的数据库:
async function copyFirebasePath(path, from, to) {
// getAccessToken from https://firebase.google.com/docs/database/rest/auth
const fromAccessToken = await getAccessToken(from.key)
const toAccessToken = await getAccessToken(to.key)
return new Promise((resolve, reject) => {
let toRequest
// create write request, but don’t start writing to it
// we’ll pipe the read request as the data to write
try {
toRequest = https.request(
`${to.databaseUrl}/${path}.json?print=silent`,
{
method: 'PUT',
headers: {
Authorization: `Bearer ${toAccessToken}`
}
},
(/* res */) => {
resolve()
}
)
} catch (writeError) {
reject(writeError)
}
try {
https
.request(
`${from.databaseUrl}/${path}.json`,
{
method: 'GET',
headers: {
Authorization: `Bearer ${fromAccessToken}`
}
},
res => {
res.pipe(toRequest)
res.on('end', () => {
toRequest.end()
})
}
)
.end()
} catch (readError) {
reject(readError)
}
})
}
我们这样使用它:
// get Object.keys from remote db
const shallowDB = await request({
method: 'get',
// note ?shallow=true here – prevents loading the whole db!
url: `${from.databaseUrl}/.json?shallow=true`,
options: {
headers: {
Authorization: `Bearer ${fromAccessToken}`
}
}
})
const dbKeys = Object.keys(shallowDB)
const keysToOmit = ['foo', 'bar', 'baz']
try {
await Promise.all(
dbKeys
.filter(dbKey => !keysToOmit.includes(dbKey))
.map(key => copyFirebasePath(key, from, to))
)
} catch (copyError) {
console.log(copyError)
throw new Error(copyError)
}
我们有一个 GitHub 操作,使用 firebase-tools
将数据从一个 Firebase 项目复制到另一个项目(我们使用的是最新版本,9.11.0
) package:
firebase use fromProject && firebase database:get / -o export.json
firebase use toProject && firebase database:set -y / export.json
这在我们的数据变大之前一直运行良好,现在我们收到以下错误:
FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - JavaScript heap out of memory
作为临时修复,我们也可以应用节点 --max-old-space-size
标志,这只会增加节点进程可用的内存:
node --max-old-space-size=4096 /home/runner/work/foo/foo/node_modules/firebase database:set -y / export.json
考虑到我们的数据会不断增长,我们想实施一个适当的修复,在我的理解中是通过 streaming 和 JSON 来设置数据。但是,我不确定 firebase-tools
是否允许这样做。搜索 Github 个问题没有找到任何有用的信息。
也许除了流式传输之外,还有另一种有用的方法可以在设置之前将巨大的 JSON 文件分成块?
谢谢!
我们使用 Firebase HTTP 的 HTTP 流 API 来克服保存、本地修改和上传巨大(超过 256mb)JSON 文件的麻烦。
我们构建了一个函数,用于将数据流从一个项目的数据库传输到另一个项目的数据库:
async function copyFirebasePath(path, from, to) {
// getAccessToken from https://firebase.google.com/docs/database/rest/auth
const fromAccessToken = await getAccessToken(from.key)
const toAccessToken = await getAccessToken(to.key)
return new Promise((resolve, reject) => {
let toRequest
// create write request, but don’t start writing to it
// we’ll pipe the read request as the data to write
try {
toRequest = https.request(
`${to.databaseUrl}/${path}.json?print=silent`,
{
method: 'PUT',
headers: {
Authorization: `Bearer ${toAccessToken}`
}
},
(/* res */) => {
resolve()
}
)
} catch (writeError) {
reject(writeError)
}
try {
https
.request(
`${from.databaseUrl}/${path}.json`,
{
method: 'GET',
headers: {
Authorization: `Bearer ${fromAccessToken}`
}
},
res => {
res.pipe(toRequest)
res.on('end', () => {
toRequest.end()
})
}
)
.end()
} catch (readError) {
reject(readError)
}
})
}
我们这样使用它:
// get Object.keys from remote db
const shallowDB = await request({
method: 'get',
// note ?shallow=true here – prevents loading the whole db!
url: `${from.databaseUrl}/.json?shallow=true`,
options: {
headers: {
Authorization: `Bearer ${fromAccessToken}`
}
}
})
const dbKeys = Object.keys(shallowDB)
const keysToOmit = ['foo', 'bar', 'baz']
try {
await Promise.all(
dbKeys
.filter(dbKey => !keysToOmit.includes(dbKey))
.map(key => copyFirebasePath(key, from, to))
)
} catch (copyError) {
console.log(copyError)
throw new Error(copyError)
}