A few days back we received a notification regarding 'Lambda operational notification' to update our Node.js 8.10 runtime to Node.js 10.x runtime.
In response to this notification, we installed Node.js version v10.16.3 in our development system and tested our existing code. We found the code was running fine in our development system, but when we tested this same code in AWS Lambda with Node.js 10.x runtime we get this following error:
2019-10-28T12:03:31.771Z 8e2472b4-a838-4ede-bc70-a53aa41d9b79 INFO Error: Server terminated early with status 127 at earlyTermination.catch.e (/var/task/node_modules/selenium-webdriver/remote/index.js:251:52) at process._tickCallback (internal/process/next_tick.js:68:7)
'aws-sdk', 'selenium-webdriver' npm packages and google chrome binaries are the only dependencies used in our project.
Our project has the following file structure.
/var/task/
├── index.js
├── lib
│ ├── chrome
│ ├── chromedriver
│ ├── libgconf-2.so.4
│ ├── libORBit-2.so.0
│ └── libosmesa.so
└── node_modules
├── selenium-webdriver
├── ...
Since this code is not throwing any error in our development system, we suspect it has to do with the new runtime.
We tried the setting the binary path using setChromeBinaryPath()
This is the code we are using. The error occurs when the build() method is called.
var webdriver = require('selenium-webdriver');
var chrome = require('selenium-webdriver/chrome');
var builder = new webdriver.Builder().forBrowser('chrome');
var chromeOptions = new chrome.Options();
const defaultChromeFlags = [
'--headless',
'--disable-gpu',
'--window-size=1280x1696', // Letter size
'--no-sandbox',
'--user-data-dir=/tmp/user-data',
'--hide-scrollbars',
'--enable-logging',
'--log-level=0',
'--v=99',
'--single-process',
'--data-path=/tmp/data-path',
'--ignore-certificate-errors',
'--homedir=/tmp',
'--disk-cache-dir=/tmp/cache-dir'
];
chromeOptions.setChromeBinaryPath("/var/task/lib/chrome");
chromeOptions.addArguments(defaultChromeFlags);
builder.setChromeOptions(chromeOptions);
var driver = await builder.build();
We recently faced the exact same issue. After upgrading to AWS Lambda Node v10.x from Node v8.x, chrome and chromedriver stopped working. In short, the root cause is that Lambda Node 10.x runs on Amazon Linux 2 Vs Lambda Node v8 which runs on Amazon Linux. Amazon Linux 2 lacks a number of packages comparing to it's predecessor, making it more lightweight but at the same time a pain in case you want to set up a custom runtime environment. Before I give you the steps to resolve this, let me first highlight a few useful links that helped me find the right set of binaries I had to also include in my lambda deployment package.
Just remember! The way to resolve this is to figure out which binaries are missing from your Lambda deployment package and add them in.
So, here is what you need to do:
sudo yum install -y yum-utils rpmdevtools
cd /tmp
mkdir lib
cd lib
yumdownloader --resolve GConf2 glibc glib2 libblkid libffi libgcc libmount libsepol libstdc++ libuuid pcre zlib libselinux dbus-glib mozjs17 polkit polkit-pkla-compat libX11 libX11-common libXau libxcb fontconfig expat fontpackages-filesystem freetype stix-fonts gnu-free-sans-fonts fontpackages-filesystem gnu-free-fonts-common nss nspr nss-softokn nss-softokn-freebl nss-util dbus-libs audit-libs bzip2-libs cracklib elfutils-libelf elfutils-libs libattr libcap libcap-ng libcrypt libdb libgcc libgcrypt libgpg-error libsepol lz4 pam systemd-libs xz-libs mesa-libOSMesa-devel mesa-libOSMesa mesa-libglapi sqlite
rpmdev-extract *rpm
sudo mkdir -p /var/task
sudo chown ec2-user:ec2-user /var/task
cd /var/task
mkdir lib
mkdir fonts
/bin/cp /tmp/lib/*/usr/lib64/* /var/task/lib
/bin/cp /tmp/lib/*/lib64/* /var/task/lib
/bin/cp /tmp/lib/*/usr/share/fonts/*/*.ttf /var/task/fonts
zip -r ./lib.zip ./*
<?xml version="1.0"?>
<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
<fontconfig>
<dir>/var/task/fonts/</dir>
<cachedir>/tmp/fonts-cache/</cachedir>
<config></config>
</fontconfig>
process.env.FONTCONFIG_PATH = `${process.env.LAMBDA_TASK_ROOT}/fonts`;
if (process.env.LD_LIBRARY_PATH.startsWith("/var/task/lib:") !== true) {
process.env.LD_LIBRARY_PATH = [...new Set(["/var/task/lib", ...process.env.LD_LIBRARY_PATH.split(':')])].join(':');
}
docker pull lambci/lambda
docker run --rm -v "$THE_LOCAL_DIR_OF_YOUR_UNCOMPRESSED_LAMDA_PACKAGE":/var/task lambci/lambda:nodejs10.x index.handler
const childProcess = require('child_process');
childProcess.execFileSync(`${process.env.LAMBDA_TASK_ROOT}/lib/chrome`);
This is a cumbersome process, but at the end of the day, all you are doing is just adding some more binaries into your package and 3 lines of code in your handler to update the lib and fonts environment variables.
Just in case, adding below as well the chrome flags we are using:
const defaultChromeFlags = [
"--headless",
"--disable-gpu",
"--window-size=1280x1024",
"--no-sandbox",
"--user-data-dir=/tmp/user-data",
"--hide-scrollbars",
"--enable-logging",
"--v=99",
"--single-process",
"--data-path=/tmp/data-path",
"--ignore-certificate-errors",
"--homedir=/tmp",
"--disk-cache-dir=/tmp/cache-dir"
];
Good luck!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With