Fix final-review findings for Playwright fallback
- server.js: catch browser-launch failures inside the injected fetchAndExtractPriceViaBrowser wrapper so they route through checkProduct's normal error classification (recordCheckFailure) instead of escaping as a thrown error that bypasses the DB write. - server.js: add an in-flight guard around runCheck so overlapping callers (cron + check-now) share one run instead of each launching its own Chromium. - Dockerfile: copy only package.json/package-lock.json/node_modules before installing Chromium so the expensive install layer is keyed to dependency changes, not every commit; copy the rest of the app afterward. - Dockerfile: clean up apt package lists after the Playwright install step, matching the build stage's existing cleanup. - README.md: note that exercising the fallback locally (not just running the test suite) needs `npx playwright install chromium`. - README.md: correct the fallback description — domcontentloaded navigation reads the page before most client-side JS finishes, so the fallback mainly helps with HTTP-client blocking, not JS-rendered prices; reworded to drop the inaccurate claim. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013gwc3aCiyQxmCWQke8RvEz
This commit is contained in:
+4
-1
@@ -8,8 +8,11 @@ COPY . .
|
||||
|
||||
FROM node:22-slim
|
||||
WORKDIR /app
|
||||
COPY --from=build /app/package.json /app/package-lock.json ./
|
||||
COPY --from=build /app/node_modules ./node_modules
|
||||
RUN npx --yes playwright install --with-deps chromium \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
COPY --from=build /app .
|
||||
RUN npx --yes playwright install --with-deps chromium
|
||||
ENV NODE_ENV=production
|
||||
# De SQLite-database hoort op het persistente volume te staan; zonder deze
|
||||
# default zou een vergeten DB_PATH stilletjes naar de container-fs schrijven
|
||||
|
||||
@@ -19,6 +19,11 @@ app bij het opstarten met een melding.
|
||||
De UI staat achter basic auth (`BASIC_AUTH_USER` / `BASIC_AUTH_PASS`) op
|
||||
`http://localhost:3000`.
|
||||
|
||||
Wil je de headless-browser-fallback ook echt lokaal uitproberen (de
|
||||
testsuite gebruikt fakes en heeft hier geen echte browser voor nodig), run
|
||||
dan eerst `npx playwright install chromium` om de Chromium-binary te
|
||||
downloaden.
|
||||
|
||||
## Environment variables
|
||||
|
||||
| Variabele | Omschrijving |
|
||||
@@ -43,6 +48,6 @@ controleren"-knop in de UI kan dit ook handmatig getriggerd worden.
|
||||
Als het ophalen van de prijs op de gewone manier mislukt (netwerkfout, of
|
||||
geen prijs gevonden in de HTML), probeert de app het één keer opnieuw met
|
||||
een echte headless-browser (Playwright/Chromium) — nuttig voor pagina's
|
||||
die de prijs pas met JavaScript renderen, of die eenvoudige HTTP-clients
|
||||
blokkeren. Geen garantie tegen elke vorm van bot-detectie, maar dekt een
|
||||
reëel deel van de gevallen die de gewone aanpak mist.
|
||||
die eenvoudige HTTP-clients blokkeren. Geen garantie tegen elke vorm van
|
||||
bot-detectie, maar dekt een reëel deel van de gevallen die de gewone
|
||||
aanpak mist.
|
||||
|
||||
@@ -37,7 +37,18 @@ function summarize(results) {
|
||||
return parts.length > 0 ? parts.join(' ') : 'geen producten';
|
||||
}
|
||||
|
||||
async function runCheck() {
|
||||
let inFlightCheck = null;
|
||||
function runCheck() {
|
||||
if (inFlightCheck) {
|
||||
return inFlightCheck;
|
||||
}
|
||||
inFlightCheck = runCheckOnce().finally(() => {
|
||||
inFlightCheck = null;
|
||||
});
|
||||
return inFlightCheck;
|
||||
}
|
||||
|
||||
async function runCheckOnce() {
|
||||
const products = listProducts(db);
|
||||
let browserPromise = null;
|
||||
function getBrowser() {
|
||||
@@ -50,8 +61,12 @@ async function runCheck() {
|
||||
const deps = {
|
||||
fetchAndExtractPrice,
|
||||
fetchAndExtractPriceViaBrowser: async (url) => {
|
||||
const browser = await getBrowser();
|
||||
return fetchAndExtractPriceViaBrowser(browser, url);
|
||||
try {
|
||||
const browser = await getBrowser();
|
||||
return await fetchAndExtractPriceViaBrowser(browser, url);
|
||||
} catch (err) {
|
||||
return { price: null, method: null, error: err };
|
||||
}
|
||||
},
|
||||
sendMail: (payload) => sendPriceChangeEmail(transport, {
|
||||
from: process.env.SMTP_FROM,
|
||||
|
||||
Reference in New Issue
Block a user