Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Puppeteer throws launch exception when deployed on azure functions node on Linux

Problem: Using puppeteer to get the screengrab of a website. Works fine on dev machine but throws below exception when deployed to Azure Functions on the cloud.

Environment: on Azure(Node 12, Linux, Consumption plan), Function triggered using service bus topic.

Error:

Result: Failure Exception: Error: Failed to launch the browser process! spawn 
/home/site/wwwroot/node_modules/puppeteer/.local-chromium/linux-818858/chrome-linux/chrome 
EACCES TROUBLESHOOTING: https://github.com/puppeteer/puppeteer/blob/main/docs/troubleshooting.md 
Stack: Error: Failed to launch the browser process! 
spawn /home/site/wwwroot/node_modules/puppeteer/.local-chromium/linux-818858/chrome-linux/chrome 
EACCES TROUBLESHOOTING: https://github.com/puppeteer/puppeteer/blob/main/docs/troubleshooting.md 
at onClose (/home/site/wwwroot/node_modules/puppeteer/lib/cjs/puppeteer/node/BrowserRunner.js:193:20) 
at ChildProcess.<anonymous> (/home/site/wwwroot/node_modules/puppeteer/lib/cjs/puppeteer/node/BrowserRunner.js:185:85)
at ChildProcess.emit (events.js:314:20) at Process.ChildProcess._handle.onexit (internal/child_process.js:274:12)
at onErrorNT (internal/child_process.js:470:16) at processTicksAndRejections (internal/process/task_queues.js:84:21)

I followed the recommendations that are on puppeteer troubleshoot document but still having the same issue.

Things I tried for lunch setting

let browser = await puppeteer.launch({ ignoreDefaultArgs: ['--disable-extensions'] });

let browser = await puppeteer.launch({ headless: true, args: ['--no-sandbox', '--disable-setuid-sandbox'] });

let browser = await puppeteer.launch({ headless: true });   

let browser = await puppeteer.launch({ args: ['--no-sandbox', '--disable-setuid-sandbox'] });

None of the above worked. They all throw the same error.

I checked FTPing into the function and the chrome file puppeteer is looking for, exists.

Thanks in advance.

like image 260
Venkata K. C. Tata Avatar asked Oct 15 '25 02:10

Venkata K. C. Tata


2 Answers

Azure has the necessary dependencies for running headless Chromium in the Linux Consumption plan. So we can use the package puppeteer in Azure function. But we need to deploy the app using remote build. For more details, please refer to the Azure feedback and the blog.

For example

  1. Create Azure function app enter image description here

  2. Create Azure function project

a. Install package

  npm install puppeteer

b. function.json

{
  "bindings": [
    {
      "name": "mySbMsg",
      "type": "serviceBusTrigger",
      "direction": "in",
      "topicName": "bowman1012",
      "subscriptionName": "test",
      "connection": "bowman1012_SERVICEBUS"
    },
    {
      "type": "blob",
      "direction": "out",
      "name": "outputBlob",
      "path": "outcontainer/{rand-guid}.png",
      "connection": "AzureWebJobsStorage"
    }
  ]
}

c. code

const puppeteer = require("puppeteer");

module.exports = async function (context, mySbMsg) {
  context.log(
    "JavaScript ServiceBus topic trigger function processed message",
    mySbMsg
  );
  const browser = await puppeteer.launch({ headless: true });
  const page = await browser.newPage();
  await page.goto("https://google.com/");
  const screenshotBuffer = await page.screenshot({ fullPage: true });
  await browser.close();
  context.bindings.outputBlob = screenshotBuffer;
};

  1. Add .funcignore file in the root project folder
*.js.map
*.ts
.git*
.vscode
local.settings.json
test
tsconfig.json
node_modules
  1. Deploy to Azure
func azure functionapp publish $appName --build remote
  1. Test enter image description here enter image description here

Update

Since you use typescript to create Azure function, we need to update .funcignore as the following

*.js.map
.git*
.vscode
local.settings.json
test
node_modules

For example

My function code index.ts

import { AzureFunction, Context } from "@azure/functions";
import { ServiceBusMessage } from "@azure/service-bus";
import puppeteer from "puppeteer";
import { BlobServiceClient } from "@azure/storage-blob";

const serviceBusTopicTrigger: AzureFunction = async function (
  context: Context,
  mySbMsg: ServiceBusMessage
): Promise<void> {
  try {
    const promotionId = context.bindingData.userProperties.promotionId;
    context.log(
      "Player Screen Grabber ServiceBus topic trigger function processing message started",
      promotionId
    );
    const playerURL = "https://www.google.com/";
    let browser = await puppeteer.launch({ headless: true });
    let page = await browser.newPage();
    await page.goto(playerURL, { waitUntil: "networkidle2" });
    await page.setViewport({ width: 1920, height: 1080 });
    const screenshotBuffer = await page.screenshot({
      encoding: "binary",
    });
    await page.close();
    await browser.close();
    // the storage account connection string
    const constr = process.env["AzureWebJobsStorage"] + "";
    const blobserviceClient = BlobServiceClient.fromConnectionString(constr);
    const containerClient = blobserviceClient.getContainerClient(
      "outcontainer"
    );
    const blob = containerClient.getBlockBlobClient(`${promotionId}.png`);
    await blob.uploadData(screenshotBuffer);
    context.log(
      "Player Screen Grabber ServiceBus topic trigger function processing message ended",
      promotionId
    );
  } catch (error) {
    throw error;
  }
};

export default serviceBusTopicTrigger;

Deploy to Azure

func azure functionapp publish $appName --build remote

Test

My service bus message enter image description here

result enter image description here enter image description here

like image 184
Jim Xu Avatar answered Oct 17 '25 15:10

Jim Xu


2023 update to @JimXu's response:

We now also need to specify a location where puppeteer will be downloaded by creating a .puppeteerrc.cjs file:

// .puppeteerrc.cjs
const path = require('path');

module.exports = {
  cacheDirectory: path.join(__dirname, '.cache', 'puppeteer')
};
like image 37
Iheb KHEMISSI Avatar answered Oct 17 '25 16:10

Iheb KHEMISSI



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!