Javascript Firebase云功能太慢
我有一个云函数,它接收图像的uid,并将其与用户关联,用户在验证其尺寸并生成其缩略图后调用它。它看起来很简单,但我必须等待大约40秒才能看到结果,有时它会变得拥挤或其他什么,我必须再次调用该函数才能看到以前的结果 以前有人经历过吗?我怎样才能解决这个问题Javascript Firebase云功能太慢,javascript,firebase,google-cloud-platform,google-cloud-firestore,google-cloud-functions,Javascript,Firebase,Google Cloud Platform,Google Cloud Firestore,Google Cloud Functions,我有一个云函数,它接收图像的uid,并将其与用户关联,用户在验证其尺寸并生成其缩略图后调用它。它看起来很简单,但我必须等待大约40秒才能看到结果,有时它会变得拥挤或其他什么,我必须再次调用该函数才能看到以前的结果 以前有人经历过吗?我怎样才能解决这个问题 exports.validateImageDimensions = functions .region("us-central1") .runWith({ memory: "2GB", timeo
exports.validateImageDimensions = functions
.region("us-central1")
.runWith({ memory: "2GB", timeoutSeconds: 120 })
.https.onCall(async (data, context) => {
正如你所看到的,CPU使用率很高
谢谢
更新
功能代码:
exports.validateImageDimensions = functions
.region("us-central1")
.runWith({ memory: "2GB", timeoutSeconds: 120 })
.https.onCall(async (data, context) => {
// Libraries
const admin = require("firebase-admin");
const sizeOf = require("image-size");
const url = require("url");
const https = require("https");
const sharp = require("sharp");
const path = require("path");
const os = require("os");
const fs = require("fs");
// Lazy initialization of the Admin SDK
if (!is_validateImageDimensions_initialized) {
admin.initializeApp();
is_validateImageDimensions_initialized = true;
}
// Create Storage
const storage = admin.storage();
// Create Firestore
const firestore = admin.firestore();
// Get the image's owner
const owner = context.auth.token.uid;
// Get the image's info
const { id, description, location, tags } = data;
// Photos's bucket
const bucket = storage.bucket("bucket");
// File Path
const filePath = `photos/${id}`;
// Get the file
const file = getFile(filePath);
// Check if the file is a jpeg image
const metadata = await file.getMetadata();
const isJpgImage = metadata[0].contentType === "image/jpeg";
// Get the file's url
const fileUrl = await getUrl(file);
// Get the photo dimensions using the `image-size` library
https.get(url.parse(fileUrl), (response) => {
let chunks = [];
response
.on("data", (chunk) => {
chunks.push(chunk);
})
.on("end", async () => {
// Check if the image has valid dimensions
let dimensions = sizeOf(Buffer.concat(chunks));
// Create the associated Firestore's document to the valid images
if (isJpgImage && hasValidDimensions(dimensions)) {
// Create a thumbnail for the uploaded image
const thumbnailPath = await generateThumbnail(filePath);
// Get the thumbnail
const thumbnail = getFile(thumbnailPath);
// Get the thumbnail's url
const thumbnailUrl = await getUrl(thumbnail);
try {
await firestore
.collection("posts")
.doc(owner)
.collection("userPosts")
.add({
id,
uri: fileUrl,
thumbnailUri: thumbnailUrl, // Useful for progress images
description,
location,
tags,
date: admin.firestore.FieldValue.serverTimestamp(),
likes: [], // At the first time, when a post is created, zero users has liked it
comments: [], // Also, there aren't any comments
width: dimensions.width,
height: dimensions.height,
});
// TODO: Analytics posts counter
} catch (err) {
console.error(
`Error creating the document in 'posts/{owner}/userPosts/' where 'id === ${id}': ${err}`
);
}
} else {
// Remove the files that are not jpeg images, or whose dimensions are not valid
try {
await file.delete();
console.log(
`The image '${id}' has been deleted because it has invalid dimensions.
This may be an attempt to break the security of the app made by the user '${owner}'`
);
} catch (err) {
console.error(`Error deleting invalid file '${id}': ${err}`);
}
}
});
});
/* ---------------- AUXILIAR FUNCTIONS ---------------- */
function getFile(filePath) {
/* Get a file from the storage bucket */
return bucket.file(filePath);
}
async function getUrl(file) {
/* Get the public url of a file */
const signedUrls = await file.getSignedUrl({
action: "read",
expires: "01-01-2100",
});
// signedUrls[0] contains the file's public URL
return signedUrls[0];
}
function hasValidDimensions(dimensions) {
// Posts' valid dimensions
const validDimensions = [
{
width: 1080,
height: 1080,
},
{
width: 1080,
height: 1350,
},
{
width: 1080,
height: 750,
},
];
return (
validDimensions.find(
({ width, height }) =>
width === dimensions.width && height === dimensions.height
) !== undefined
);
}
async function generateThumbnail(filePath) {
/* Generate thumbnail for the progressive images */
// Download file from bucket
const fileName = filePath.split("/").pop();
const tempFilePath = path.join(os.tmpdir(), fileName);
const thumbnailPath = await bucket
.file(filePath)
.download({
destination: tempFilePath,
})
.then(() => {
// Generate a thumbnail using Sharp
const size = 50;
const newFileName = `${fileName}_${size}_thumb.jpg`;
const newFilePath = `thumbnails/${newFileName}`;
const newFileTemp = path.join(os.tmpdir(), newFileName);
sharp(tempFilePath)
.resize(size, null)
.toFile(newFileTemp, async (_err, info) => {
// Uploading the thumbnail.
await bucket.upload(newFileTemp, {
destination: newFilePath,
});
// Once the thumbnail has been uploaded delete the temporal file to free up disk space.
fs.unlinkSync(tempFilePath);
});
// Return the thumbnail's path
return newFilePath;
});
return thumbnailPath;
}
});
Pd:在控制台中,我可以读取以下记录:
"Function execution took 103 ms, finished with status code: 200"
但是,正如我之前所说,我必须等待大约40秒,才能在我的firestore上看到新的文档您没有正确处理承诺。可调用函数必须返回以下承诺:
请注意,它是异步的,并在调用其回调之前立即返回。您需要找到一种方法来返回一个承诺,当回调的所有工作都完成时,该承诺就会得到解决。(考虑到还有其他HTTP客户机库,它们可以更容易地获得承诺,而不必处理回调。)如果不了解实际功能,很难回答您的问题,可能它的效率不高,导致等待时间长。另外,您的云函数使用2GB的RAM运行,而不是CPU。我在函数配置中看到,如果我设置更高的RAM,函数也会有更多的CPU。@是的,我已经用完整的代码更新了这个问题。可能这与firestore中的一些延迟有关。如果您使用硬编码的值创建测试对象,是否也需要40秒才能显示?您已经发现问题在于:https.get(url.parse(fileUrl),(response)=>{let chunks=[];response.on(“data”,(chunk)=>{chunks.push(chunk);})。on(“end”,async()=>{….如果我将之前的图像关联上传到firestore,我可以在1秒内看到结果。我应该返回void吗?我的意思是,在客户端,我不希望从函数得到响应,我使用了https.onCall,因为我认为这是一种从应用程序调用云函数的方法。无论客户端是否希望得到响应您需要发送一个。HTTP就是这样工作的。返回一个承诺,该承诺与要发送的数据或至少一些伪数据(如空对象)进行解析。该承诺必须在所有异步工作完全完成后才能解析,否则异步工作将不会按您期望的方式运行。伙计,您是一个天才,只需完全按照您所说的去做,并获得正确的结果即可在一秒钟内得到结果。非常感谢!希望有一天能像你一样专业地使用javascript:D