Rails Support

Important: These docs are for the outdated Jets 5 versions and below. For the latest Jets docs: docs.rubyonjets.com

Update 10/26/2023: The Rails experimental support has been broken for a while. It has been removed in Jets v5 to prepare for a version of Rails support that will be container based. There is currently no timeline. These docs are only kept around for posterity.

Jets Afterburner mode supports deploying your Rails app requiring little changes to your code. This is an experimental feature.

How It Works

Jets Afterburner mode works by starting a rack subprocess in the Lambda Execution Context and then a normal Jets application proxies to that server. This is accomplished via Jets Mega Mode. All of this happens transparently. You just deploy from your rails application folder.

Usage

If your Rails application uses environment variables such as DATABASE_URL or DATABASE_PASSWORD, Jets needs to know about them prior to deployment in order to make them available to the generated Lambda functions. You should set the variables in .env files which should be placed in your Rails project’s .jets/project/ directory. Be sure to read the .env file documentation so that you know how to name your .env files.

$ cd <your Rails project directory>
$ mkdir -p .jets/project
$ touch .jets/project/.env # you should add your environment variables here

Once your .env files are configured, just do the following to deploy your Rails app:

$ gem install jets # note: do not add jets to your Rails project's Gemfile
$ jets deploy
=> Rails app detected: Enabling Jets Afterburner to deploy to AWS Lambda.
...
Deploying CloudFormation stack with jets app!
05:05:11PM UPDATE_IN_PROGRESS AWS::CloudFormation::Stack demo-rails-dev User Initiated
...
05:06:48PM UPDATE_COMPLETE AWS::CloudFormation::Stack demo-rails-dev
Stack success status: UPDATE_COMPLETE
Time took for stack deployment: 1m 36s.
Prewarming application.
API Gateway Endpoint: https://jp65zxlwf8.execute-api.us-west-2.amazonaws.com/dev/
$

Setting the Project Name

By default, Jets will infer the project name from the folder you are in. You can override this with a special .jets/project/project_name file. The first line in .jets/project/project_name will be used as the project name if the file exists.

Advanced customizations

If you want to make Lambda-specific application-wide configurations, you can add config files in the .jets/project directory. For example, you can set the Lamba function memory size for the production environment inside of .jets/project/config/environments/production.rb:

Jets.application.configure do
  config.function.memory_size = 1024
end

Read the documentation for Function Properties to learn about other properties which can be set.

Notes and Considerations

  • Do not add jets to your Rails project’s Gemfile. Adding it to the Gemfile might result in bundler being unable to resolve dependencies. Jets is used as a stand-alone tool in Afterburner mode.
  • Afterburner mode provides a way to run Rails on Serverless but is not a panacea for all Rails applications. Each and every Rails application is different and likely makes assumptions that it’s running on a traditional server not serverless.
  • For example, the app might upload files or images to the filesystem. This doesn’t work on AWS Lambda because the app doesn’t have access to a persistent filesystem. The application would have to be reworked to store files on a distributed store like S3 instead.
  • Also, AWS currently limits the total Lambda code size + Gem Layer to 250MB. AWS Docs Lambda Limits. The baseline Rails gems add up to about 146MB, so you have about 104MB of space left for additional gems.
  • For more complex Rails apps, you might want to consider looking into Jets Mega Mode. Mega Mode allows you to selectively run parts of your app in Rails and parts in Jets.
  • Most apps just make more sense to run as a Jets app. Jets was built and specifically designed for the serverless world.

Rails with Jets vs Straight Jets

Generally, it is recommended you run Jets application directly instead of Afterburner mode. Though mostly hidden from a user perspective, there is overhead associated and extra obfuscation with Jets Afterburner. This Mega Mode Post may help.

Though it is possible to leverage Jets features in Afterburner by adding code to .jets/project, it’s recommended to run Jets natively when possible. When you run a Jets application natively, you also get direct access to the full power of Jets. Some examples are Jobs, Events, and IAM Policies.

JavaScript Runtime Error

If the Rails rack process fails to start up and you see this error in the CloudWatch logs:

/opt/ruby/gems/2.5.0/gems/execjs-2.7.0/lib/execjs/runtimes.rb:58:in `autodetect': Could not find a JavaScript runtime. See https://github.com/rails/execjs for a list of available runtimes. (ExecJS::RuntimeUnavailable)

This is because Rails includes the uglifier and coffee-rails gems, which depend on a javascript runtime. The error means a javascript runtime like node was not found. In recent versions of the AWS Lambda Ruby Runtime, it looks like node is no longer installed. To fix this, uncomment therubyracer in your Gemfile. Uglifier will detect that therubyracer javascript runtime is available and use that instead.

Another approach that seems to work is to move the uglifier and coffee-rails gems in the Gemfile development group. Jets does not bundle gems in the development group as a part of deployment to Lambda.

Endpoint request timed out Error

If you are seeing a Endpoint request timed out error, it is probably because the rack subprocess failed to start. For performance, the rack subprocess is started outside the lambda handler function and only runs in the cold-start.

Try going farther up the CloudWatch logs to find out where rackup is failing to start. That is the key. It may help to run jets deploy again and watch the logs during deployment time. The usual errors are a database connection issue or a gem dependency issue.