Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PhantomJS in AWS Lambda (Missing libfontconfig)

I am trying to get my lambda function to use phantomjs, however it keeps running into an error of a missing dependency: libfontconfig / fontconfig. On my Centos VPS when I install fontconfig (dnf install fontconfig -y) my code works fine. However when running on lambda I cannot figure out how to get this library to be ran with my function.

This is my code: (Attempting to get the best selling products through the AliExpress package, which uses phantomjs)

const aliExpress = require('aliexpress');

exports.handler = (event, context, callback) => {
    console.log('Handler ran!');
    aliExpress.BestSelling.get().then((goods) => {
        console.log('Found results!');
        const urls = [];
        for(let index in goods) {
            const url = goods[index].url;
            urls.push(url);
        }
        console.log('Returning URLs:');
        console.log(urls);
        callback(null, urls);
    }).catch((err) => {
        console.log('Error:');
        console.log(err);
        callback(err);
    });
};

// For testing on VPS
exports.handler(null, null, (err, result) => {
    if(err) {
        console.log('Err:');
        console.log(err);
    } else {
        console.log('Result:');
        console.log(result);
    }
});

I am expecting the result to be an array of AliExpress URLs, this is what happens whenever I run it with fontconfig installed on my VPS. However, on my lambda function AND on my VPS without fontconfig installed I am getting this error:

Handler ran!
(node:1966) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): Error: Error reading from stdin: Error: write EPIPE
(node:1966) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
error: /home/function/node_modules/phantomjs-prebuilt/lib/phantom/bin/phantomjs: error while loading shared libraries: libfontconfig.so.1: cannot open shared object file: No such file or directory

I believe I now either have to 1) Figure out how to run phantomjs without this dependency or 2) Figure out how to install this dependency to my Lambda function's "server"

Perhaps there's a previous version of phantomjs that gives me the functionality I want without this dependency? Not sure

Anyone know how I can solve this problem? Thank you!

like image 726
Alexzander Flores Avatar asked Dec 02 '17 01:12

Alexzander Flores


People also ask

How to use Phantom JS on lambda with Node JS 10?

Using phantom js on lambda with nodejs 10 and 12 is not directly possible, it becase it misses few dependencies like libfontconfig.so on the newer amazon linux 2 base image. To overcome this problem you have to use your own fonts folder which contains the required files and a font.conf file

How to add fonts in AWS Lambda V2?

If you want to add fonts in AWS Lambda V2 as it does not appear to support even the basic fonts on its own, create a directory called “/fonts” on your distribution package and include the fonts.conf inside the folder (this is a very stripped version):

Why can't I Run my AWS Lambda code in Python?

I receive the "Unable to import module" error when I try to run my AWS Lambda code in Python. You typically receive this error when your Lambda environment can't find the specified library in the Python code. This is because Lambda isn't prepackaged with all Python libraries.

How do I use Lambda with AWS publish-layer-version?

Create an AWS Identity and Access Management (IAM) role with permissions to call the publish-layer-version API. Then, attach the IAM role to the EC2 instance. Note: Your EC2 instance now has permissions to upload Lambda layers for the publish-layer-version API call.


2 Answers

Here's what I just got to work for custom fonts on AWS Lambda with pandoc/xelatex. I'd bet you can adapt it to do something similar for your use case.

I created a fonts directory in my project and placed all of my fonts there. Also in that directory I created a fonts.conf file that looks like this:

<?xml version="1.0"?>
<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
<fontconfig>
  <dir>/var/task/fonts/</dir>
  <cachedir>/tmp/fonts-cache/</cachedir>
  <config></config>
</fontconfig>

And then in my (node.js based) handler function before shelling out to call pandoc I set an ENV var to tell fontconfig where to find the fonts.

process.env.FONTCONFIG_PATH='/var/task/fonts'

After doing that I can refer to a font, like Bitter, in my template by name (just Bitter) and then pandoc/xelatex/fontconfig/whatever knows which version of the font to use (like Bitter-Bold.otf vs Bitter-Italic.otf) based on the styling that any bit of text is supposed to have.

I figured this out based on the tips in this project for getting RSVG to work with custom fonts on Lambda: https://github.com/claudiajs/rsvg-convert-aws-lambda-binary/blob/master/README.md#using-custom-fonts

like image 91
Jeremy Green Avatar answered Oct 21 '22 19:10

Jeremy Green


For those ending up there, here's my little story: I wanted to use a Roboto font to generate html-template-based PDF with phantomJs on a AWS Lambda execution.

My application 'App' is in nodeJs and depends on a 'RunTimeDep' dependency which executes a bunch of useful stuff for App at runtime. Among those tasks, it generates a PDF based on a html template, in which I wanted to use Roboto Mono. Just to mention, the html template is in 'App'.

To do so, I created the /fonts folder as @Jeremy Green mentionned in the 'RunTimeDep' module. I converted the Roboto fonts into PFB format, and put them there. I added thus this fonts.conf:

<?xml version="1.0"?>
<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
<fontconfig>
  <dir>/var/task/node_modules/RunTimeDep/fonts/</dir>
  <cachedir>/tmp/fonts-cache/</cachedir>
  <config></config>
</fontconfig>

Finally, I added the FONTCONFIG_PATH to point to /var/task/node_modules/RunTimeDep/fonts/ (I used serverless envrionment variable, but process.env should be fine too)

And this actually worked just great

like image 1
Thomas Vuillaume Avatar answered Oct 21 '22 19:10

Thomas Vuillaume