Как я могу заставить AWS Lambda получать доступ к гемам, хранящимся в vendor / bundle?

Я пишу функцию Lambda на Ruby, которая в конечном итоге будет отправлять мне некоторые уведомления в Slack через Webhook. Итак, что у меня есть для моего файла lambda_function, это

require 'json'
require 'webhook'

def lambda_handler(event:, context:)
    # TODO implement
    { statusCode: 200, body: JSON.generate('Hello from Lambda!') }
    Webhook.post('https://mywebhookurl', {message: 'test'})
end

И структура каталогов в моем встроенном редакторе кода выглядит так:

Gemfile
Gemfile.lock
lambda_function.rb
vendor/
  bundle/
    ruby
      2.3.0
        gems/webhook

также под ванной 2.3.0 есть несколько других папок, включая build_info, cache, doc и т. д. Чтобы разместить этот код на AWS Lambda, я запускаю

zip -r myLambda.zip *, чтобы собрать все в zip-архив и загрузить в Lambda.

Однако когда я наконец запускаю базовый тест лямбда-выражения, я получаю следующую ошибку:

{
  "errorMessage": "cannot load such file -- webhook",
  "errorType": "Init<LoadError>",
  "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/lambda_function.rb:2: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'"
  ]
}

Больше этого быть не должно, поскольку следующий учебник показывает, как именно настроить то, что у меня есть, но не работает. Кому-нибудь удалось извлечь драгоценные камни из своего гем-файла в AWS Lambda?

🤔 А знаете ли вы, что...
Ruby поддерживает различные парадигмы программирования, включая функциональное программирование.


13
5 637
3

Ответы:

Вам необходимо убедиться, что версия Ruby, которую вы использовали локально для сборки, соответствует версии, используемой Lambda.

Похоже, что в вашем zip-архиве драгоценные камни установлены в 2.3.0, но в вашем списке трассировки стека указано 2.5.0. Это несоответствие означает, что лямбда-бегун не может найти ваши драгоценные камни.


Я столкнулся с этой же проблемой при создании слоев AWS Lambda с Ruby. Быстрый и простой способ заставить это работать - добавить все пути к гемам в Ruby $ LOAD_PATH в AWS Lambda. IE:

load_paths = Dir["/opt/ruby/gems/2.5.0/**/lib"]
$LOAD_PATH.unshift(*load_paths)

require 'webhook'

Замените "/opt/ruby/gems/2.5.0/**/lib" на "./vendor/bundle/ruby/2.3.0/gems/**/lib" в вашем случае.

Когда вы выполняете require 'webhook', он перебирает все пути, находит "./vendor/bundle/ruby/2.3.0/gems/webhook-1.0.0/lib/webhook.rb" и добавляет его в вашу AWS Lambda. require не требует расширения файла.

Когда мы запускаем rails через упаковщик, он творит для нас кучу «волшебства», включая проверку того, что наш $ LOAD_PATH указывает на драгоценные камни. Поскольку AWS Lambdas не использует сборщик пакетов, нам нужно сделать часть этой «магии» самостоятельно.


Я думаю, вам не следует изменять GEM_PATH или устанавливать $LOAD_PATH во всех лямбда-функциях. «Лучший» способ - это проделать эту небольшую хитрость при создании архива слоев:

bundle install --path vendor/bundle
cd vendor/bundle
mkdir ruby/gems
mv ruby/2.5.0 ruby/gems/
zip -r layer.zip ruby/gems/2.5.0/