bump
ci/woodpecker/push/woodpecker Pipeline was successful Details

This commit is contained in:
Colin 2025-11-30 21:30:49 -05:00
parent 85ddbf561d
commit 049db7424f
Signed by: colin
SSH Key Fingerprint: SHA256:nRPCQTeMFLdGytxRQmPVK9VXY3/ePKQ5lGRyJhT5DY8
1 changed files with 96 additions and 15 deletions

View File

@ -122,27 +122,108 @@ async function generatePdf(browser, htmlFile) {
timeout: 30000 timeout: 30000
}); });
// Wait a bit for any JavaScript to finish // Wait for includes.js to finish loading header and footer
// Check if header-include element exists and has content
try {
await page.waitForFunction(() => {
const headerInclude = document.getElementById('header-include');
const footerInclude = document.getElementById('footer-include');
// If neither element exists, page doesn't use includes - that's fine
if (!headerInclude && !footerInclude) return true;
// If header exists but is empty, wait
if (headerInclude && headerInclude.innerHTML.trim() === '') return false;
// If footer exists but is empty, wait
if (footerInclude && footerInclude.innerHTML.trim() === '') return false;
// If header exists, check if nav is loaded (indicates includes.js finished)
if (headerInclude) {
const nav = headerInclude.querySelector('nav');
if (!nav) return false;
}
return true;
}, {
timeout: 15000,
polling: 100 // Check every 100ms
});
} catch (waitError) {
// If waiting for includes times out, continue anyway
// Some pages might not use includes or might load differently
console.warn(`Warning: Includes may not have fully loaded for ${htmlFile}, continuing anyway...`);
}
// Additional wait for any remaining JavaScript to finish
await page.waitForTimeout(1000); await page.waitForTimeout(1000);
// Generate PDF // Generate PDF with retry logic for transient errors
await page.pdf({ let retries = 2;
path: pdfPath, let lastError = null;
format: 'A4',
printBackground: true,
margin: {
top: '20mm',
right: '15mm',
bottom: '20mm',
left: '15mm'
}
});
console.log(`✓ Generated: ${pdfRelativePath}`); while (retries > 0) {
try {
await page.pdf({
path: pdfPath,
format: 'A4',
printBackground: true,
margin: {
top: '20mm',
right: '15mm',
bottom: '20mm',
left: '15mm'
}
});
console.log(`✓ Generated: ${pdfRelativePath}`);
return; // Success, exit retry loop
} catch (pdfError) {
lastError = pdfError;
// Check if it's a recoverable error
if (pdfError.message.includes('detached') ||
pdfError.message.includes('closed') ||
pdfError.message.includes('Target closed')) {
retries--;
if (retries > 0) {
console.warn(`Retrying PDF generation for ${htmlFile} (${retries} attempts remaining)...`);
// Wait a bit before retrying
await page.waitForTimeout(2000);
// Re-navigate to the page if it was closed
try {
await page.goto(url, {
waitUntil: 'networkidle0',
timeout: 30000
});
await page.waitForTimeout(1000);
} catch (navError) {
// If navigation fails, break out of retry loop
break;
}
}
} else {
// Non-recoverable error, don't retry
throw pdfError;
}
}
}
// If we get here, all retries failed
throw lastError || new Error('PDF generation failed after retries');
} catch (error) { } catch (error) {
console.error(`✗ Failed: ${htmlFile} - ${error.message}`); console.error(`✗ Failed: ${htmlFile} - ${error.message}`);
} finally { } finally {
await page.close(); try {
await page.close();
} catch (closeError) {
// Ignore close errors - page may have been closed already
// This can happen if the page navigated or was closed during processing
// Common error: "Protocol error: Connection closed" or "Target closed"
if (!closeError.message.includes('closed') && !closeError.message.includes('Target closed')) {
// Only log if it's not a "page already closed" error
console.warn(`Warning closing page for ${htmlFile}: ${closeError.message}`);
}
}
} }
} }