Search code examples
node.jsfirebasegoogle-cloud-functionsphantomjsnode-html-pdf

Receiving error: html-pdf: PDF generation timeout. Phantom.js script did not exit. within Firebase Cloud Functions


I'm building out a firebase function that uses the html-pdf package (which uses PhantomJS). The function works fine on my local machine, but whenever I deploy the function on Firebase, I get the following error:

Error: html-pdf: PDF generation timeout. Phantom.js script did not exit.

I've changed the timeout parameter for pdf.create() and keep getting the same result. Any idea on what might be creating this issue that is unique to only when a deploy this to Firebase? Code is below.

const pdf = require('html-pdf');
const runtimeOpts = {
    timeoutSeconds: 540,  // in seconds
    memory: '2GB'
  }

exports.sendToKindle = functions.runWith(runtimeOpts).https.onRequest(async (req, res) => {
   // REMOVED A BLOCK OF CODE FOR SIMPLICITY, BUT CAN PUT BACK IN IF NEEDED//
   var options = { 
       format: 'Letter',
       directory: "/tmp", 
       timeout: 540000,  // in milliseconds
   };
    
   const blookFileName = createFileName(blookData.title) + '.pdf';
    
   const tempFilePath = path.join(os.tmpdir(), `${blookFileName}`);

   const htmlFilePath = path.join(os.tmpdir(), 'book.html');

   const htmlFs = fs.openSync(htmlFilePath, 'w');

   await fs.promises.appendFile(htmlFilePath, bookHTML);

   const fd = fs.openSync(tempFilePath, 'w');

   var html = fs.readFileSync(htmlFilePath, 'utf8');

   let mailgunObject = null;

   pdf.create(html, options).toFile(tempFilePath, async (err, res) => {
           if (err) return console.error(err);
           mailgunObject = await sendEmail(tempFilePath, kindleEmail);
           return console.log(res);
       });

   fs.closeSync(fd);
   fs.closeSync(htmlFs);

   return cors(req, res, () => {
        res.status(200).type('application/json').send({'response': 'Success'})
    })

Solution

  • I was able to solve this issue by modifying the code by having the pdf.create().toFile() placed within the return of the cloud function.

    const pdf = require('html-pdf');
    const runtimeOpts = {
        timeoutSeconds: 300,  // in seconds
        memory: '1GB'
      }
    
    exports.sendToKindle = functions.runWith(runtimeOpts).https.onRequest(async (req, res) => {
       // REMOVED A BLOCK OF CODE FOR SIMPLICITY, BUT CAN PUT BACK IN IF NEEDED//
       var options = { 
           format: 'Letter',
           directory: "/tmp", 
           timeout: 540000,  // in milliseconds
       };
        
       const blookFileName = createFileName(blookData.title) + '.pdf';
        
       const tempFilePath = path.join(os.tmpdir(), `${blookFileName}`);
    
       const htmlFilePath = path.join(os.tmpdir(), 'book.html');
    
       const htmlFs = fs.openSync(htmlFilePath, 'w');
    
       await fs.promises.appendFile(htmlFilePath, bookHTML);
    
       const fd = fs.openSync(tempFilePath, 'w');
    
       var html = fs.readFileSync(htmlFilePath, 'utf8');
    
       return cors(req, res, () => {
            pdf.create(html, options).toFile(tempFilePath, async (err, res) => {
               if (err) return console.error(err);
               let mailgunObject = await sendEmail(tempFilePath, kindleEmail);
               fs.closeSync(fd);
               fs.closeSync(htmlFs);
               return console.log(res);
            });
    
            res.status(200).type('application/json').send({'response': 'Success'})
        })