3

I intend to create an AWS lambda function using Ruby 2.7 with Selenium. When I try to run my example function i get:

{
  "errorMessage": "unable to connect to /opt/chromedriver 127.0.0.1:9515",
  "errorType": "Function<Selenium::WebDriver::Error::WebDriverError>",
  "stackTrace": [
    "/var/task/vendor/bundle/ruby/2.7.0/gems/selenium-webdriver-4.3.0/lib/selenium/webdriver/common/service_manager.rb:138:in `connect_until_stable'",

Which is confusing to me because the file is located in that path. I have created a AWS layer with both chromedriver and chromium headless. After creating the layers i have attached them to the function. The error when the files are not there is different so I am assuming it can reach the files.

My sample program is:

require 'json'
require 'selenium-webdriver'

def lambda_handler(event:, context:)
  driver = setup_driver
  driver.navigate.to 'http://www.google.com'
  element = driver.find_element(name: 'q')
  element.send_keys 'Pizza'
  element.submit
  title = driver.title
  driver.quit
  { statusCode: 200, body: JSON.generate(title) }
end

def setup_driver
  service = Selenium::WebDriver::Service.chrome(path: '/opt/chromedriver')
  Selenium::WebDriver.for :chrome, service: service, options: driver_options
end

def driver_options
  options = Selenium::WebDriver::Chrome::Options.new(binary: '/opt/headless-chromium')
  options.add_argument('--no-sandbox')
  options.add_argument('--headless')
  options.add_argument("--window-size=#{800},#{600}")
  options.add_argument('--disable-popup-blocking')
  options.add_argument('--disable-gpu')
  options.add_argument('--disable-dev-shm-usage')
  options.add_argument('--single-process')
  return options
end

Update:

After locating the proper chromedriver and installing google chrome from the yum repo i managed to get it to work locally.

Here is my Dockerfile

FROM public.ecr.aws/lambda/ruby:2.7
COPY . ${LAMBDA_TASK_ROOT}
RUN bundle config --local silence_root_warning true
RUN bundle install --path vendor/bundle --clean
# USER root
RUN yum -y install wget unzip

# Chromium
COPY google-chrome.repo /etc/yum.repos.d/google-chrome.repo
RUN yum install google-chrome-stable -y

# Chromedriver
RUN wget https://chromedriver.storage.googleapis.com/102.0.5005.61/chromedriver_linux64.zip
RUN unzip chromedriver_linux64.zip -d /usr/bin/
RUN rm chromedriver_linux64.zip

CMD [ "lambda_function.lambda_handler" ]

When i run it locally with:

docker run -p 9000:8080 prueba 

And test it in a different terminal:

curl -XPOST "http://localhost:9000/2015-03-31/functions/function/invocations" -d '{"payload":"hello world!"}'

{"statusCode":200,"body":"\"Pizza - Buscar con Google\""}%                                                      

It works wonderful!!!

However when deploying it (By publishing the docker image in the ECR and creating a lambda using given docker image) i get the following error:

{
  "errorMessage": "Net::ReadTimeout with #<TCPSocket:(closed)>",
  "errorType": "Function<Net::ReadTimeout>",
  "stackTrace": [
    "/var/lang/lib/ruby/2.7.0/net/protocol.rb:217:in `rbuf_fill'",
    "/var/lang/lib/ruby/2.7.0/net/protocol.rb:191:in `readuntil'",
    "/var/lang/lib/ruby/2.7.0/net/protocol.rb:201:in `readline'",
    "/var/lang/lib/ruby/2.7.0/net/http/response.rb:42:in `read_status_line'",
    "/var/lang/lib/ruby/2.7.0/net/http/response.rb:31:in `read_new'",
    "/var/lang/lib/ruby/2.7.0/net/http.rb:1528:in `block in transport_request'",
    "/var/lang/lib/ruby/2.7.0/net/http.rb:1519:in `catch'",
    "/var/lang/lib/ruby/2.7.0/net/http.rb:1519:in `transport_request'",
    "/var/lang/lib/ruby/2.7.0/net/http.rb:1492:in `request'",
    "/var/task/vendor/bundle/ruby/2.7.0/gems/selenium-webdriver-4.3.0/lib/selenium/webdriver/remote/http/default.rb:118:in `response_for'",
    "/var/task/vendor/bundle/ruby/2.7.0/gems/selenium-webdriver-4.3.0/lib/selenium/webdriver/remote/http/default.rb:77:in `request'",
    "/var/task/vendor/bundle/ruby/2.7.0/gems/selenium-webdriver-4.3.0/lib/selenium/webdriver/remote/http/common.rb:59:in `call'",
    "/var/task/vendor/bundle/ruby/2.7.0/gems/selenium-webdriver-4.3.0/lib/selenium/webdriver/remote/bridge.rb:592:in `execute'",
    "/var/task/vendor/bundle/ruby/2.7.0/gems/selenium-webdriver-4.3.0/lib/selenium/webdriver/remote/bridge.rb:52:in `create_session'",
    "/var/task/vendor/bundle/ruby/2.7.0/gems/selenium-webdriver-4.3.0/lib/selenium/webdriver/common/driver.rb:314:in `block in create_bridge'",
    "/var/task/vendor/bundle/ruby/2.7.0/gems/selenium-webdriver-4.3.0/lib/selenium/webdriver/common/driver.rb:312:in `tap'",
    "/var/task/vendor/bundle/ruby/2.7.0/gems/selenium-webdriver-4.3.0/lib/selenium/webdriver/common/driver.rb:312:in `create_bridge'",
    "/var/task/vendor/bundle/ruby/2.7.0/gems/selenium-webdriver-4.3.0/lib/selenium/webdriver/common/driver.rb:74:in `initialize'",
    "/var/task/vendor/bundle/ruby/2.7.0/gems/selenium-webdriver-4.3.0/lib/selenium/webdriver/common/driver.rb:47:in `new'",
    "/var/task/vendor/bundle/ruby/2.7.0/gems/selenium-webdriver-4.3.0/lib/selenium/webdriver/common/driver.rb:47:in `for'",
    "/var/task/vendor/bundle/ruby/2.7.0/gems/selenium-webdriver-4.3.0/lib/selenium/webdriver.rb:89:in `for'",
    "/var/task/lambda_function.rb:19:in `setup_driver'",
    "/var/task/lambda_function.rb:7:in `lambda_handler'"
  ]
}

I have already added memory and timeout seconds to the lambda function but it still fails. This is odd because it works locally but not on the actual AWS Lambda.

damuz91
  • 1,461
  • 2
  • 21
  • 37
  • Hi, Use WATIR which is the wrapper around ruby selenium binding . If you still face the same problem, then tag the watir tag and raise your question. – Rajagopalan Jun 27 '22 at 15:10
  • Thank you, will try that right now and post updates here – damuz91 Jun 27 '22 at 21:14
  • @Rajagopalan same issue here. I think the problem is not the Selenium per se but the actual chromedriver + chrome binary needed :( – damuz91 Jun 28 '22 at 16:46
  • 1
    I know but I asked you to do under WATIR because the maintainers of ruby selenium are the maintainers of WATIR as well. They only look at watir tag. – Rajagopalan Jun 28 '22 at 17:15
  • 1
    Could you try [this](https://stackoverflow.com/a/33898828/19330634) ? – l -_- l Jul 07 '22 at 13:20
  • Thank you mysterious user heheh. Although it would work adding Timeout would not be reasonable for a production environment :(, but off course I will try it. Thank you! – damuz91 Jul 08 '22 at 20:15
  • Did you manage to figure this out? I've been stuck on this exact same problem for days - tried it with Lambda layers, then a Docker container, all with no luck. (I can't even get it to work locally using a Docker container.) – jayp Aug 22 '22 at 13:40
  • 1
    No my friend, I abandoned this idea on desperation and tears. I rather build up an EC2 instance using AL2 x86 and a ruby app :( – damuz91 Aug 24 '22 at 16:35

0 Answers0