我正在开发一个aws lambda,它需要为bucket中的每个新s3对象启动一个puppeteer浏览器,浏览器启动代码在初始调用时花费了很长时间,所以我想我应该把启动代码放在处理程序之外,并使用Provisioned Concurrency来使浏览器在新文件插入bucket时准备就绪。
它似乎调用了promise,因为在进行任何实际调用之前,我会收到日志,上面写着“从配置的并发示例中获取可执行路径。但是,在进行实际的lambda调用之前,它从来没有输出消息“启动浏览器”。如果promise chromium.executablePath在处理程序之外,为什么在进行调用之前它不会完成?
let startTime = Date.now();
const chromium = require("chrome-aws-lambda");
const AWS = require("aws-sdk");
const s3 = new AWS.S3();
const { createSSRApp } = require("vue");
const { renderToString } = require("vue/server-renderer");
const path = require("path");
const fs = require("fs");
const manifest = require("../../compiled/ssr-manifest.json");
console.log("Load packages: " + (Date.now() - startTime));
const browserPromise = new Promise((res) => {
const browserStartTime = Date.now();
console.log("Getting executable path");
chromium.executablePath.then((executablePath) => {
console.log("Launching browser");
chromium.puppeteer
.launch({
args: chromium.args,
defaultViewport: chromium.defaultViewport,
executablePath: executablePath,
headless: true,
})
.then((browser) => {
res(browser);
console.log("Start headless browser: " + (Date.now() - browserStartTime));
});
});
});
browserPromise.then(() => console.log("Started Headless Browser"));
/**
* A Lambda function that logs the payload received from S3.
*/
exports.handler = async (event, context) => {
const bucketName = event.Records[0].s3.bucket.name;
const objectKey = event.Records[0].s3.object.key;
const browser = await browserPromise;
... //use browser code
}
如果我需要这个文件在本地的另一个节点文件中,它可以很好地运行promise,而不需要调用handler函数,所以这一定是一些我不理解的lambda环境特定的东西。有人对此有什么见解吗?
1条答案
按热度按时间nfzehxib1#
您所描述的问题是由于对异步代码的控制不佳造成的。
延迟示例化浏览器承诺
当您使用
new
关键字示例化Promise
时,您提供的函数将立即开始执行。这将立即打印
'test'
,而不需要.then
或await
,这就是为什么您的代码立即打印'Getting executable path'
,而不是等待lambda的请求事件。要解决这个问题,在请求真正发生之前不要示例化这个承诺,将你的承诺构造移到一个函数中,当请求发生时,你可以从处理程序中调用它。
修复异步返回流
第二,你需要让你的
startBrowser
函数实际返回一个浏览器。因为你还没有await
编辑任何在你的browserPromise
中创建的承诺,它会触发代码启动chromium,但会立即解决。浏览器启动需要一段时间,这就是为什么你直到很久以后才看到'Launching browser'
。若要解决此问题,请确保在浏览器准备就绪之前不会解析浏览器承诺,然后返回浏览器对象以便使用。
通过跨请求共享浏览器来提高性能
您可以通过将浏览器保存为单例来进一步提高性能,这样就不需要在每个请求周期都示例化一个新浏览器。
有关内存使用情况的说明
浏览器可能会占用大量内存,也可能会泄漏内存。如果修复你的异步代码仍然不能使lambda工作,请考虑加载一个网页可能会消耗千兆字节的内存,特别是对于大型和复杂的页面(例如谷歌Map)。我对lambda没有经验,但你可能会发现自己遇到内存限制。