使用Firebase Admin SDK存实时数据库:关连接丢数据,不关程序挂起
Firebase Admin SDK 实时数据库写入后程序挂起/数据丢失问题解决
问题根源分析
你的问题核心出在两处:
- 异步操作未等待:
coinRef.set()是异步Promise操作,但代码里没有等待它执行完成就继续后续逻辑。如果提前调用goOffline,写请求还没同步到服务器就被中断,导致数据丢失;如果不关闭连接,Firebase的实时长连接会保持活跃,Node.js进程不会自动退出,造成程序挂起。 - App重复初始化隐患:
getDB()每次调用都会执行admin.initializeApp(),这不符合Firebase Admin SDK的规范——App实例必须是单例,重复初始化会抛出异常(当前未触发是因为可能只调用了一次,但属于错误写法)。
修正后的代码实现
1. 修复数据库实例的单例初始化
import * as cert from './ebay-prices-admin.js'; import admin from 'firebase-admin'; // 单例存储数据库实例,避免重复初始化App let dbInstance = null; export function getDB() { // 仅在无已初始化App时执行初始化 if (!admin.apps.length) { const serviceAccount = cert['default']; admin.initializeApp({ credential: admin.credential.cert(serviceAccount), databaseURL: "removed" // 替换为你的数据库URL }); } // 复用已创建的数据库实例 if (!dbInstance) { dbInstance = admin.database(); } return dbInstance; }
2. 等待所有异步写入操作完成
export async function addCoin(db, search, coins) { try { const ref = db.ref(search); // 收集所有写入操作的Promise,批量等待完成 const writeTasks = coins.map(coin => { const coinRef = ref.child(revisedRandId()); return coinRef.set({ name: coin.name, price: coin.price, shipping: coin.shipping, date: coin.date }); }); // 等待所有写入请求同步到服务器 await Promise.all(writeTasks); console.log('所有数据已成功写入数据库'); } catch (error) { console.error('数据写入失败:', error); } }
正确的程序结束流程
必须等所有写入操作完成后,再主动关闭Firebase连接,确保Node.js进程正常退出:
// 示例调用逻辑 async function run() { const db = getDB(); // 替换为你的实际数据 const coinsData = [{name: "测试币", price: 10, shipping: 0, date: new Date()}]; // 等待写入完成 await addCoin(db, 'coin-search', coinsData); // 所有操作完成后关闭连接 await admin.database().goOffline(); } run().catch(err => console.error(err));
额外说明
coinRef.off()在这里无需调用,因为代码仅执行写入操作,没有监听数据变化,不存在需要移除的监听器。- 只有当所有
set的Promise状态变为resolved后,才能执行关闭连接的操作,否则会导致未完成的写请求被中断。
内容的提问来源于stack exchange,提问作者dede
相关产品推荐
相关产品推荐

