0

Here's a service I'm running on a Debian 10 VPS:

require("dotenv").config();
const express = require("express");
const puppeteer = require("puppeteer");
const app = express();

app.use(express.json());

app.post("/create-inbox", (req, res) => {
    if (!req.body["firstName"] || !req.body["lastName"]) return res.status(400).json({ Error: "firstName and lastName are required." });

    let firstName = req.body["firstName"];
    let lastName = req.body["lastName"];

    res.status(202).json({ firstName: firstName, lastName: lastName});    
    createInbox(firstName, lastName);
})

app.listen(process.env.PORT);

async function createInbox(firstName, lastName) {
    const browser = await puppeteer.launch({ headless: true });
    console.log(`Browser opened`);
    const page = await browser.newPage();
    await page.setDefaultNavigationTimeout(0);
    await page.setDefaultTimeout(0);
    await page.goto("https://app.mailparser.io/account/login", {
        waitUntil: 'domcontentloaded'
    });
    console.log(`Loaded ${page.url()}`);
    await page.type("#email", process.env.MP_ACCT);
    await page.type("#password", process.env.MP_PASS);
    await page.click("#start-free-sub");
    await page.waitForNavigation({ waitUntil: "domcontentloaded" });
    console.log(`Loaded ${page.url()}`);
    await page.click("#dashboard_inbox_add");
    await page.type("input[name='label']", `${firstName} ${lastName}`);
    await page.select("select[name='inbox_category_id']", "3015");
    // hangs here on second run
    await Promise.all([
        page.waitForNavigation({ waitUntil: "domcontentloaded" }),
        page.click("#btn_add_address_save"),
    ]);
    console.log("after save");
    await browser.close();
    console.log(`Browser closed`);
}

This seems to run just fine the first time I start the service, but when I try to use the route again it hangs right at the Promise.all(...). console.log("after save") will only show up after the first run.

Promise.all(...) was the solution proposed here: Puppeteer hanging on page.click()

As well as the official solution in the Puppeteer documentation

I'm at a loss for what to try next.

  • Did you try `Promise.all()` around the nav triggered by clicking `#start-free-sub`? Setting all timeouts to infinity seems like a bad idea. I would expire these after a minute or two so you can get a clear traceback and diagnose the problem, then release the browser with a `finally` block so you don't leak resources. – ggorlen Oct 21 '22 at 20:36
  • I haven't tried putting the `#start-free-sub` and waitForNav into a `Promise.all()` because it hasn't caused any issues yet. I'll test it out though and see if it helps. I do agree that the infinite timeout is not ideal. I do plan on replacing it with something more sensible once I can confirm everything is working. I did have a timeout set previously but the stack trace wasn't providing anything useful afaik. I'll check again just in case. Thanks for your input! – Anthony Evans Oct 21 '22 at 22:37
  • I wrapped the first `click` and `waitForNav` in a `Promise.all` and now it won't even run completely once. – Anthony Evans Oct 27 '22 at 18:23
  • I'd make timeouts small, 60 seconds max if the site is heavy, so you can figure out which line is triggering it. It's hard to help beyond that since we're dealing with a login. If the nav is freezing, maybe there is no nav, in which case it should probably be removed completely. But a situation with a click that triggers nav and a `waitForNav` being separate is probably wrong, so either go all-in with both and a `Promise.all` or skip the `nav` completely. Creating race conditions might appear to work, but it also might cause the script to break in unpredictable ways. – ggorlen Oct 27 '22 at 19:24

0 Answers0