Cloud Function迁移Cloud Storage大量文件时遇TLS连接断开错误求助
问题描述
将文件迁移至Cloud Storage时,测试5个文件可正常完成,但处理50个以上文件时,函数返回错误:
Exception from a finished function: FetchError: request to https://storage.googleapis.com/storage/v1/b/...-933ca.appspot.com/o?prefix=documents%123123123231321sadas failed, reason: Client network socket disconnected before secure TLS connection was established
Cloud Function代码如下:
exports.updateStorage = functions.https.onRequest(async (req, res) => { try { await updateStorageData(); res.send(200); } catch (error) { console.error('Error updating storage data', error); return error; } }); const updateStorageData = async () => { const db = admin.firestore(); db.collection('users') .get() .then(userSnapshot => { userSnapshot.forEach(user => { const userId = user.id; const subCollectionRef = db .collection('users') .doc(userId) .collection('documents'); subCollectionRef .get() .then(snapshot => { snapshot.forEach(async doc => { await readFiles({ docId: doc.id, userId }); }); }) .catch(err => { console.log('Error getting documents', err); }); }); }); }; async function readFiles({ docId, userId }) { const [files] = await admin .storage() .bucket() .getFiles({ prefix: `documents/${docId}` }); if (files.length === 0) { return; } const promises = []; files.forEach(file => { promises.push(file.copy(`users/${userId}/${file.name}`)); }); await Promise.all(promises); }
函数详情:
- First gen函数
- onRequest触发器
- 内存配置8GB
- 通过Firebase控制台的“Testing”标签页运行测试
- 需访问Firebase Firestore获取数据,并更新Cloud Storage中的文件结构
解决方案
1. 修复异步流程控制漏洞
当前代码的核心问题是异步流程失控,导致函数提前终止、请求被中断:
updateStorageData内部使用.then()但未返回Promise,await updateStorageData()会直接执行完成,函数提前结束,后续文件复制请求被强制中断,引发TLS连接错误。forEach中使用async/await无效,forEach不会等待异步函数执行,导致大量请求被同时触发,超出系统连接上限。
修改后的updateStorageData统一用async/await管理异步流程,收集所有Promise等待完成:
const updateStorageData = async () => { const db = admin.firestore(); const userSnapshot = await db.collection('users').get(); // 收集所有用户处理任务 const userTasks = userSnapshot.docs.map(async user => { const userId = user.id; const docSnapshot = await db.collection('users').doc(userId).collection('documents').get(); // 收集当前用户下所有文档的处理任务 const docTasks = docSnapshot.docs.map(doc => readFiles({ docId: doc.id, userId })); await Promise.all(docTasks); }); await Promise.all(userTasks); };
2. 限制并发请求数量
一次性触发大量文件复制会导致网络过载,可在readFiles中分批处理,控制并发数:
async function readFiles({ docId, userId }) { const [files] = await admin.storage().bucket().getFiles({ prefix: `documents/${docId}` }); if (files.length === 0) { return; } const batchSize = 10; // 可根据实际情况调整 // 分批执行文件复制 for (let i = 0; i < files.length; i += batchSize) { const batch = files.slice(i, i + batchSize); const copyTasks = batch.map(file => file.copy(`users/${userId}/${file.name}`)); await Promise.all(copyTasks); } }
3. 调整函数超时时间
First gen Cloud Function默认超时1分钟,处理大量文件时时间不足。可在函数配置中将超时时间调整至最大9分钟(First gen上限)。
4. 优化网络与配额
- 确保Cloud Function所在区域与Cloud Storage桶区域一致,减少跨区域网络延迟。
- 检查Cloud Storage的请求配额,若达到每秒请求数限制,可申请配额提升。
内容的提问来源于stack exchange,提问作者Mark James
相关产品推荐
相关产品推荐

