ruby - 如何在 AWS Lambda 中正确加载 gem 扩展

标签 ruby aws-lambda rubygems sequel pg

我在处理 AWS Lambda 上的 gem 加载错误时遇到问题。

{
  "errorMessage": "LoadError: libpq.so.5: cannot open shared object file: No such file or directory - /var/task/vendor/bundle/ruby/2.5.0/gems/pg-1.1.4/lib/pg_ext.so",
  "errorType": "Function<Sequel::AdapterNotFound>",
  "stackTrace": [
    "/var/lang/lib/ruby/2.5.0/rubygems/core_ext/kernel_require.rb:59:in `require'",
    "/var/lang/lib/ruby/2.5.0/rubygems/core_ext/kernel_require.rb:59:in `require'",
    "/var/task/vendor/bundle/ruby/2.5.0/gems/pg-1.1.4/lib/pg.rb:4:in `<top (required)>'",
    "/var/lang/lib/ruby/2.5.0/rubygems/core_ext/kernel_require.rb:59:in `require'",
    "/var/lang/lib/ruby/2.5.0/rubygems/core_ext/kernel_require.rb:59:in `require'",
    "/var/task/vendor/bundle/ruby/2.5.0/gems/sequel-5.16.0/lib/sequel/adapters/postgres.rb:6:in `<top (required)>'",
    "/var/lang/lib/ruby/2.5.0/rubygems/core_ext/kernel_require.rb:59:in `require'",
    "/var/lang/lib/ruby/2.5.0/rubygems/core_ext/kernel_require.rb:59:in `require'",
    "/var/task/vendor/bundle/ruby/2.5.0/gems/sequel-5.16.0/lib/sequel/database/connecting.rb:88:in `load_adapter'",
    "/var/task/vendor/bundle/ruby/2.5.0/gems/sequel-5.16.0/lib/sequel/database/connecting.rb:17:in `adapter_class'",
    "/var/task/vendor/bundle/ruby/2.5.0/gems/sequel-5.16.0/lib/sequel/database/connecting.rb:45:in `connect'",
    "/var/task/vendor/bundle/ruby/2.5.0/gems/sequel-5.16.0/lib/sequel/core.rb:121:in `connect'",
    "/var/task/vendor/bundle/ruby/2.5.0/gems/sequel-5.16.0/lib/sequel/core.rb:399:in `adapter_method'",
    "/var/task/vendor/bundle/ruby/2.5.0/gems/sequel-5.16.0/lib/sequel/core.rb:406:in `block (2 levels) in def_adapter_method'",
    "/var/task/lib/warehouse/loader.rb:5:in `connection'",
    "/var/task/lib/warehouse/loader.rb:24:in `initialize'",
    "/var/task/lib/warehouse/update.rb:43:in `new'",
    "/var/task/lib/warehouse/update.rb:43:in `block in handle'",
    "/var/task/lib/warehouse/update.rb:42:in `each'",
    "/var/task/lib/warehouse/update.rb:42:in `handle'",
    "/var/task/lambda.rb:11:in `handler'"
  ]
}

我正在使用 Sequel 库从 AWS Lambda 建立 PSQL 连接,但该函数似乎找不到 so 文件。我已经将依赖项打包到 vendor/bundle 中,在 Ubuntu 中构建在 CodeBuild 上,并验证 .so 文件存在于上传到 lambda 的结果工件中。我还编辑了 $LOAD_PATH,但这似乎没有帮助。

有没有人遇到过这个问题?关于解决或调试的任何进一步提示?

最佳答案

lib 文件夹中是否有 libpq.so.5

您的错误是说在 $PATH 上找不到 libpq.so.5,在 AWS Lambda 中文件夹 lib 是自动的加载到路径上,因此,您只需要将此文件放在那里。

在 lambda 世界之外创建的可执行文件不能在 Lambda 上运行,此外,您需要在 Lambda 镜像上自行编译可执行文件。这是一个如何做到这一点的例子:

gem 文件

source "https://rubygems.org"

gem "pg"
gem "mysql2"

handler.rb

require 'pg'
require 'mysql2'

def run(event:, context:)
  {
    postgres_client_version: PG.library_version,
    mysql_client_version: Mysql2::VERSION
  }
end

Dockerfile

FROM lambci/lambda:build-ruby2.5

RUN yum install -y postgresql postgresql-devel mysql mysql-devel
RUN gem update bundler

ADD Gemfile /var/task/Gemfile
ADD Gemfile.lock /var/task/Gemfile.lock

RUN bundle install --path /var/task/vendor/bundle --clean

这将构建您的镜像,然后运行它以生成 PG 和 MYSQL 可执行文件,然后将其复制到您的 lib 文件夹。

build.sh

#!/bin/bash -x
set -e

rm -rf lib && rm -rf vendor && mkdir lib && mkdir vendor

docker build -t pg_mysql_layer -f Dockerfile .

CONTAINER=$(docker run -d pg_mysql_layer false)

docker cp \
    $CONTAINER:/var/task/vendor/ \
    ./

docker cp \
    $CONTAINER:/usr/lib64/libpq.so.5.5 \
    lib/libpq.so.5

docker cp \
    $CONTAINER:/usr/lib64/mysql/. \
    lib/

docker rm $CONTAINER

运行 ./build.sh 后,它将生成文件夹 libvendor 以及您需要的所有内容,现在您只需要部署您的 lambda 函数。

要在本地进行测试,您可以运行: docker run --rm -it -v $PWD:/var/task -w/var/task lambci/lambda:ruby2.5 handler.run

它会返回类似这样的东西:

Lambda execution

编号:https://www.stevenringo.com/ruby-in-aws-lambda-with-postgresql-nokogiri/

编号:https://www.reddit.com/r/ruby/comments/a3e7a1/postgresql_on_aws_lambda_ruby/

关于ruby - 如何在 AWS Lambda 中正确加载 gem 扩展,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54330779/

相关文章:

ruby - RSpec:使用方法 stub 测试交互式用户输入

ruby - 当使用 ruby​​ 定义一系列键时,将所有键值作为组合字符串获取

ruby-on-rails - STI 和子类

ruby - 我如何 "Inherit"一个 Ruby 模块来创建另一个模块?

php - 如何使用 AWS SDK PHP 将触发器添加到 AWS Lambda 函数?

amazon-web-services - 如何更改 lambda 的默认参数值?

amazon-s3 - 参数中缺少必需的 key 'Bucket'

ruby-on-rails - Ruby On Rails:NameError:未初始化常量 Timezone::Configure

ruby-on-rails - 如何在 Windows 上安装 Linux Rails gem

ruby - 添加 gem "tesseract-ocr"Rails 4 后尝试运行服务器时出错