我有一个包含 220k 个产品的数据库,每个产品都有 1-3 个图像链接(全部小于 200kb)。我需要检查所有这些并将它们直接上传到 Google Cloud Storage,而无需在本地下载。这是我想出的方法:
const saveFileFromUrl = (sneakerData: any, size: string, index: number) => {
const imageURL: string = resolveObject(`image_${size}`, sneakerData)
if(!imageURL.includes("https://")) return("not a link")
const req = request(imageURL)
req.on('response', res => {
if(res.statusCode !== 200) return
const imageType = res.headers['content-type']?.split('/')[1]
const writeStream = storage.bucket(bucketName).file(`${sneakerData.sneaker_id}/${size}.${imageType}`).createWriteStream({
gzip: true,
metadata: {
contentType: res.headers['content-type']
}
})
req.pipe(writeStream)
.on('finish', () => console.log(`SUCCESS INDEX: ${index}`))
.on('error', ()=> {
writeStream.end();
console.log('ERROR INDEX: ' + index)
})
req.resume();
})
req.on('error', err => console.log(err))
}
const app = async() => {
const data = await getLinks();
console.log("STARTING")
for(let i in data){
for(let j in imageSizes){
await saveFileFromUrl(data[Number(i)],imageSizes[Number(j)], Number(i))
}
}
}
此脚本适用于前 ~1k 图像,但随后我再次遇到相同的错误:
Error: connect ETIMEDOUT
at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1278:16) {
errno: -4039,
code: 'ETIMEDOUT',
syscall: 'connect',
address: '',
port: 443
}
我还尝试了 Promise 方法,将 Promise 推送到数组,然后最后使用 Promise.all,但结果是相同的。
我对 Google Cloud Platform 相当陌生,因此任何提示、技巧或解决方法都会对我有很大帮助,谢谢。
您正在尝试这样做:
await saveFileFromUrl(...)
但是,
saveFileFromUrl()
不会返回承诺,因此 await
没有做任何有用的事情。这会导致您的所有上传并行运行,这显然会占用一些资源。
您可以更改
saveFileFromUrl()
以返回一个在操作完成时解析/拒绝的承诺(您必须修复一些 TypeScript 语法):
const saveFileFromUrl = (sneakerData: any, size: string, index: number) => {
return new Promise((resolve, reject) => {
const imageURL: string = resolveObject(`image_${size}`, sneakerData)
if (!imageURL.includes("https://")) {
reject("not a link");
return;
}
const req = request(imageURL);
req.on('response', res => {
if (res.statusCode !== 200) return
const imageType = res.headers['content-type']?.split('/')[1]
const writeStream = storage.bucket(bucketName).file(`${sneakerData.sneaker_id}/${size}.${imageType}`).createWriteStream({
gzip: true,
metadata: {
contentType: res.headers['content-type']
}
})
req.pipe(writeStream).on('finish', () => {
console.log(`SUCCESS INDEX: ${index}`)
resolve();
}).on('error', e => {
writeStream.end();
console.log('ERROR INDEX: ' + index)
reject(e);
});
})
req.on('error', err => {
console.log(err)
reject(err);
});
});
}