Ever since AWS released official Ruby support for AWS Lambda on Nov 29 at re:Invent, I’ve been super excited about switching Jets over to the official AWS version of Ruby. Happy to say that Jets is now on the official AWS Ruby runtime. Knew it was going to be interesting to learn about AWS Lambda Custom Runtimes and Lambda Layers as part of this Jets update.

Lambda Custom Runtimes Are Fast

The official Lambda Ruby runtime is built on top of AWS Lambda Custom Runtimes technology. Custom Runtimes allow us to add support of any language. Since Ruby is now officially supported, we do not have to create our own runtime. Though there are use-cases for this. For example, different Ruby versions.

It was fun to study and compare how Custom Runtimes work vs a traditional shim. If you have ever built your own shim yourself to support other languages, they way AWS implemented Custom Runtimes would make complete sense.

Essentially, a Custom Runtime is a custom server. The server proxies request from one language to another. This ensures that the runtime is kept in memory and fast. This is similar to how Jets achieved Native performance for Ruby before official support.

The beautiful thing about official Custom Runtimes is that the runtime gets prepackaged as part of the Lambda function creation process. Very cool!

Lambda Custom Runtime Fix

There’s an additional benefit of AWS implementing Ruby support as a Custom Runtime. When updating Jets, I ran into an issue with the actual AWS Ruby Runtime itself. The Ruby aws-sdk has it’s own version of .to_json that collides with the ActiveSupport version. The issue only seems to trigger on some aws-sdk calls like sns.publish. The cool thing about Ruby being implemented as Custom Runtime is that we can patch a fix for it now. We do not have to wait until AWS officially fixes it. Here’s the fix for the .to_json collision in Jets: lambda/marshaller.rb.

Lambda Layers: Gem Layers

AWS introduced Lambda Layers at the same time as Ruby Support. With Lambda Layers, you can add additional files to the Lambda server in the form of layers. These layers are combined together like a pancake and flattened out. From the Lambda Layers docs, AWS suggests:

With layers, you can use libraries in your function without needing to include them in your deployment package.

This helps you to keep the code package size under the key 3MB limit, thereby allowing you to use the live Lambda console code editor.

You can develop your function code in the Lambda console as long as you keep your deployment package under 3 MB.

Having the ability to change your code and debug live significantly increases your development speed and happiness. Previously, Jets accomplished this by separately packaging the dependencies and lazying loading them as part of the shim. In this Jets upgrade, that logic has all be converted to a Lambda Layer and named the Gem Layer. Once again, awesome.

Screenshot

Hopefully, you found the background info above interesting. Now here’s a Jets application running on official Ruby support.

Jets Code

For those who might not seen Jets code before, here are some examples. Here’s a simple function:

app/functions/simple.rb:

def lambda_handler(event:, context:)
  pp event
  puts "hello world"
  {foo: "bar"}
end

Here’s a Jets Controller:

app/controllers/posts_controller.rb:

class PostsController < ApplicationController
  def index
    # renders Lambda Proxy structure compatiable with API Gateway
    render json: {hello: "world", action: "index"}
  end

  def show
    id = params[:id] # params available
    # puts goes to the lambda logs
    puts event # raw lambda event available
    render json: {action: "show", id: id}
  end
end

Here’s a Jets Job.

app/jobs/hard_job.rb:

class HardJob < ApplicationJob
  class_timeout 300 # 300s or 5m, current Lambda max is 15m

  rate "10 hours" # every 10 hours
  def dig
    puts "done digging"
  end

  cron "0 */12 * * ? *" # every 12 hours
  def lift
    puts "done lifting"
  end
end

More info on the official rubyonjets.com docs.

How to Upgrade

The upgrade path is transparent. Since Jets Controllers and Jobs interfaces did not change, there’s not a lot to it:

cd project # your jets project
bundle update
jets upgrade # optional
jets deploy

The jets upgrade command is actually optional and simply gets rid of a deprecation warning for a config removal in the latest version.

That’s it! Jets is now on official AWS Ruby Support. Hope you like this article and give Jets a try. Also if you find Jets interesting, please give it ⭐️ it on GitHub. I’d appreciate it. 👍

Live Demos

Here are some additional Live Demos of Jets applications:

More examples are in the jets-examples repo.

Binary Gems

Ruby serverless applications might also use native binary gems. Jets uses Lambda Gems to make for a seamless and much easier deploy process. Lambda Gems is currently in beta, and early signups will receive a special offer for their support.

More info