Modified 'printResume' Firebase cloud function: implemented basic retry mechanism with waitUntil 'networkidle0' and 'networkidle2', enhanced error handling to return more detailed information

This commit is contained in:
gianantoniopini
2021-05-04 11:30:12 +02:00
parent 1ac828b532
commit 14ea8de709

View File

@ -54,42 +54,100 @@ const deleteUserFunctionHandler = async (_, { auth }) => {
} }
}; };
exports.deleteUser = functions /**
.runWith({ memory: '256MB' }) * Tries to navigate the page to a given URL.
.https.onCall(deleteUserFunctionHandler); *
* @param {puppeteer.Page} page Page.
* @param {string} url URL to navigate page to.
* @param {puppeteer.PuppeteerLifeCycleEvent} waitUntil When to consider navigation succeeded.
* @returns {Promise<string>} Returns null if no error occurred, otherwise returns the error message.
*/
const tryGotoPage = async (page, url, waitUntil) => {
let httpResponse;
exports.printResume = functions try {
.runWith({ memory: '1GB' }) httpResponse = await page.goto(url, {
.https.onCall(async ({ id, type }, { auth }) => { waitUntil,
if (!id) { });
throw new functions.https.HttpsError( } catch (error) {
'invalid-argument', return `page.goto (waitUntil: "${waitUntil}") threw an error with message "${error.message}"`;
'The function must be called with argument "id" containing the resume ID.', }
);
if (httpResponse === null) {
return `page.goto (waitUntil: "${waitUntil}") returned a null response`;
}
if (!httpResponse.ok()) {
return `page.goto (waitUntil: "${waitUntil}") returned a response with HTTP status ${httpResponse.status()} "${httpResponse.statusText()}"`;
}
return null;
};
/**
* Creates a page and navigates to a given URL.
*
* @param {puppeteer.Browser} browser Browser.
* @param {string} url URL to navigate to.
* @returns {Promise<{page: puppeteer.Page, errors: string[]}>} Returns an object with the page if no error occurred, otherwise returns an object with the list of error messages.
*/
const gotoPage = async (browser, url) => {
const errors = [];
const waitUntilArray = ['networkidle0', 'networkidle2'];
for (let index = 0; index < waitUntilArray.length; index++) {
/* eslint-disable no-await-in-loop */
const waitUntil = waitUntilArray[index];
const page = await browser.newPage();
await page.setCacheEnabled(false);
const error = await tryGotoPage(page, url, waitUntil);
if (!error) {
return { page, errors: null };
} }
if (!type) { errors.push(error);
throw new functions.https.HttpsError( await page.close();
'invalid-argument', }
'The function must be called with argument "type" containing the type of resume.',
);
}
if (!auth) { return { page: null, errors };
throw new functions.https.HttpsError( };
'failed-precondition',
'The function must be called while authenticated.',
);
}
const printResumeFunctionHandler = async ({ id, type }, { auth }) => {
if (!id) {
throw new functions.https.HttpsError(
'invalid-argument',
'The function must be called with argument "id" containing the resume ID.',
);
}
if (!type) {
throw new functions.https.HttpsError(
'invalid-argument',
'The function must be called with argument "type" containing the type of resume.',
);
}
if (!auth) {
throw new functions.https.HttpsError(
'failed-precondition',
'The function must be called while authenticated.',
);
}
try {
const browser = await puppeteer.launch({ const browser = await puppeteer.launch({
headless: true, headless: true,
args: ['--no-sandbox'], args: ['--no-sandbox'],
}); });
const page = await browser.newPage();
await page.goto(BASE_URL + id, { const url = BASE_URL + id;
waitUntil: 'networkidle0', const { page, errors } = await gotoPage(browser, url);
}); if (errors && errors.length > 0) {
throw new Error(errors.join(' - '));
}
await timeout(6000); await timeout(6000);
await page.emulateMediaType('print'); await page.emulateMediaType('print');
let pdf; let pdf;
@ -124,4 +182,15 @@ exports.printResume = functions
await browser.close(); await browser.close();
return Buffer.from(pdf).toString('base64'); return Buffer.from(pdf).toString('base64');
}); } catch (error) {
throw new functions.https.HttpsError('internal', error.message);
}
};
exports.deleteUser = functions
.runWith({ memory: '256MB' })
.https.onCall(deleteUserFunctionHandler);
exports.printResume = functions
.runWith({ memory: '1GB' })
.https.onCall(printResumeFunctionHandler);