Reputation: 1292
I'm writing a Lambda function in Ruby which will eventually send me some notifications in Slack via Webhook. So what I have for my lambda_function
file is
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
And the directory structure in my inline code editor looks like this:
Gemfile
Gemfile.lock
lambda_function.rb
vendor/
bundle/
ruby
2.3.0
gems/webhook
also under the 2.3.0
bath are several other folders including build_info
, cache
, doc
etc. In order to get this code onto AWS Lambda, I'm running
zip -r myLambda.zip *
to get everything into a zip file and uploaded to Lambda.
However, when I finally go to run a basic test on the lambda, I get the following error:
{
"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'"
]
}
There shouldn't be any more to this as the following tutorial shows exactly how to set up what I have, but doesn't work. Does anyone have success pulling gems from their gemfile in AWS Lambda?
Upvotes: 15
Views: 7725
Reputation: 1988
I think you should not change the GEM_PATH or having to set $LOAD_PATH
in every lambda functions.
The "best" way is to do this little hack when you create the layer archive:
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/
Upvotes: 5
Reputation: 5521
I ran into this same problem when building AWS Lambda Layers w/ Ruby. A quick and easy way to get this to work is to add all of the gem paths to Ruby's $LOAD_PATH in your AWS Lambda. IE:
load_paths = Dir["/opt/ruby/gems/2.5.0/**/lib"]
$LOAD_PATH.unshift(*load_paths)
require 'webhook'
Replace "/opt/ruby/gems/2.5.0/**/lib"
with "./vendor/bundle/ruby/2.3.0/gems/**/lib"
in your case.
When you do require 'webhook'
it's going to go and look through all of the paths and come across "./vendor/bundle/ruby/2.3.0/gems/webhook-1.0.0/lib/webhook.rb"
and add it into your AWS Lambda. require
doesn't require a file extension.
When we run rails through bundler it does a bunch of 'magic' for us including making sure that our $LOAD_PATH is pointing at the gems. Since AWS Lambdas don't use bundler, we need to do some of this 'magic' ourselves.
Upvotes: 19
Reputation: 542
You need to make sure the version of Ruby you used locally to bundle matches the version used by Lambda.
Your zip appears to have the gems installed in 2.3.0 but your stack trace lists 2.5.0. This mismatch means lambda runner can’t find your gems.
Upvotes: 14