puppeteer-sharp icon indicating copy to clipboard operation
puppeteer-sharp copied to clipboard

Pre-download Chromium with code during deployment to prevent slow cold-starts

Open maikelvanhaaren opened this issue 2 years ago • 6 comments

First of all, thank you for the effort you're putting into this package!

We recently made a transition from using NodeJS to .NET (Linux) for our consumption-based Azure Function, for various reasons. In our previous setup with NodeJS, we utilized puppeteer, and now we're using puppeteer-sharp. I've noticed a difference in the way these two packages handle the downloading of Chromium.

In the NodeJS setup, Chromium was downloaded during the npm install process, whereas with puppeteer-sharp, it is downloaded at runtime. This disparity, combined with the nature of serverless Azure Functions, occasionally leads to errors, especially during a cold start, when Chromium hasn't been downloaded yet.

Is there a way we can address this issue? One potential solution could be bundling Chromium together with the Azure Functions code so that it doesn't need to be downloaded at runtime.

maikelvanhaaren avatar May 23 '23 13:05 maikelvanhaaren

I wrote this post a few years ago. I hope it still works. But the solution would be using containers in azure functions.

kblok avatar May 23 '23 13:05 kblok

Check, thanks for the link. That also seems like a potential solution for this by including chromium within the container.

I was experimenting today by upgrading the Azure Function from Dynamic to an enterprise plan so I can have minimal one instance warm at all times in the hope to reduce the cold-start errors. On the dynamic SKU, it's all working but on the enterprise plan with the same code, puppeteer-sharp fails at launching the browser (error while loading shared libraries: libgobject-2.0.so.0: cannot open shared object file: No such file or directory).

What do you think about an option where you have the possibility to bring-your-own-chromium (BYOC)? Something like:

await browserFetcher.SetupPredownloadedChromium(package: "../chromium-linux.zip").ConfigureAwait(false);

var chromiumExecutablePath = browserFetcher.RevisionInfo(BrowserFetcher.DefaultChromiumRevision).ExecutablePath;
var launchOptions = new LaunchOptions
{
	Headless = true,
	Args = new[] { "--no-sandbox --font-render-hinting=none" },
	ExecutablePath = chromiumExecutablePath
};

await using var browser = await Puppeteer.LaunchAsync(launchOptions).ConfigureAwait(false);

maikelvanhaaren avatar May 23 '23 14:05 maikelvanhaaren

I think I tried that in the past, back in 2019. Maybe give it chance to see if that works?

kblok avatar May 23 '23 14:05 kblok

Is there a branch open with your attempt? I'm happy to give it a try.

maikelvanhaaren avatar May 23 '23 14:05 maikelvanhaaren

No. I discarded that attempt.

kblok avatar May 23 '23 14:05 kblok

OK, check. I'm gonna give it a try and see what I can come up with so we have some more concrete things to discuss 😄

maikelvanhaaren avatar May 23 '23 14:05 maikelvanhaaren