• Stars
    star
    155
  • Rank 240,864 (Top 5 %)
  • Language
    Ruby
  • License
    MIT License
  • Created almost 4 years ago
  • Updated over 1 year ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

ActiveJob on SQS & Lambda

Lambdakiq: ActiveJob on SQS & Lambda

Test

Lambdakiq

Lamby: Simple Rails & AWS Lambda Integration using Rack. A drop-in replacement for Sidekiq when running Rails in AWS Lambda using the Lamby gem.

Lambdakiq allows you to leverage AWS' managed infrastructure to the fullest extent. Gone are the days of managing pods and long polling processes. Instead AWS delivers messages directly to your Rails' job functions and scales it up and down as needed. Observability is built in using AWS CloudWatch Metrics, Dashboards, and Alarms. Learn more about Using AWS Lambda with Amazon SQS or get started now.

Key Features

  • Distinct web & jobs Lambda functions.
  • AWS fully managed polling. Event-driven.
  • Maximum 12 retries. Per job configurable.
  • Mirror Sidekiq's retry backoff timing.
  • Last retry is at 11 hours 30 minutes.
  • Supports ActiveJob's wait/delay. Up to 15 minutes.
  • Dead messages are stored for up to 14 days.

Project Setup

This gem assumes your Rails application is on AWS Lambda, ideally with our Lamby gem. It could be using Lambda's traditional zip package type or the newer container format. If Rails on Lambda is new to you, consider following our quick start guide to get your first application up and running. From there, to use Lambdakiq, here are steps to setup your project

Bundle & Config

Add the Lambdakiq gem to your Gemfile.

gem 'lambdakiq'

Open config/environments/production.rb and set Lambdakiq as your ActiveJob queue adapter.

config.active_job.queue_adapter = :lambdakiq

Open app/jobs/application_job.rb and add our worker module. The queue name will be set by an environment using CloudFormation further down.

class ApplicationJob < ActiveJob::Base
  include Lambdakiq::Worker
  queue_as ENV['JOBS_QUEUE_NAME']
end

Using ActionMailer's built-in deliver job with ActiveJob? Make sure to include the Lambdakiq worker and set the queue name depending on your Rails version. You can do this in a newly created config/initializers//action_mailer.rb or another initializer of your choice.

# Rails 5.x
ActionMailer::DeliveryJob.include Lambdakiq::Worker
ActionMailer::DeliveryJob.queue_as ENV['JOBS_QUEUE_NAME']
# Rails 6.x
ActionMailer::MailDeliveryJob.include Lambdakiq::Worker
ActionMailer::MailDeliveryJob.queue_as ENV['JOBS_QUEUE_NAME']

The same Docker image will be used for both your web and jobs functions (example setup in following sections). The Lamby gem can automatically can detect if Lambdakiq is present when using the newer Lamby.cmd or older lower Lamby.handler method. That said, please take a look at the JobsLambda in the following section and how ImageConfig is used as the golden path for sharing containers.

SQS Resources

Open up your project's SAM template.yaml file and make the following additions and changes. First, we need to create your SQS queues under the Resources section.

JobsQueue:
  Type: AWS::SQS::Queue
  Properties:
    ReceiveMessageWaitTimeSeconds: 10
    RedrivePolicy:
      deadLetterTargetArn: !GetAtt JobsDLQueue.Arn
      maxReceiveCount: 13
    VisibilityTimeout: 301

JobsDLQueue:
  Type: AWS::SQS::Queue
  Properties:
    MessageRetentionPeriod: 1209600

In this example above we are also creating a queue to automatically handle our redrives and storage for any dead messages. We use long polling to receive messages for lower costs. In most cases your message is consumed almost immediately. Sidekiq polling is around 10s too.

The max receive count is 13 which means you get 12 retries. This is done so we can mimic Sidekiq's automatic retry and backoff. The dead letter queue retains messages for the maximum of 14 days. This can be changed as needed. We also make no assumptions on how you want to handle dead jobs.

Queue Name Environment Variable

We need to pass the newly created queue's name as an environment variable to your soon to be created jobs function. Since it is common for your Rails web and jobs functions to share these, we can leverage SAM's Globals section.

Globals:
  Function:
    Environment:
      Variables:
        RAILS_ENV: !Ref RailsEnv
        JOBS_QUEUE_NAME: !GetAtt JobsQueue.QueueName

We can remove the Environment section from our web function and all functions in this stack will now use the globals. Here we are using an intrinsic function to pass the queue's name as the JOBS_QUEUE_NAME environment variable.

IAM Permissions

Both functions will need capabilities to access the SQS jobs queue. We can add or extend the SAM Policies section of our RailsLambda web function so it (and our soon to be created jobs function) have full capabilities to this new queue.

Policies:
  - Version: "2012-10-17"
    Statement:
      - Effect: Allow
        Action:
          - sqs:*
        Resource:
          - !Sub arn:aws:sqs:${AWS::Region}:${AWS::AccountId}:${JobsQueue.QueueName}

Overview

Now we can duplicate our RailsLambda resource YAML (except for the Events property) to a new JobsLambda one. This gives us a distinct Lambda function to process jobs whose events, memory, timeout, and more can be independently tuned. However, both the web and jobs functions will use the same ECR container image!

JobsLambda:
  Type: AWS::Serverless::Function
  Metadata:
    DockerContext: ./.lamby/RailsLambda
    Dockerfile: Dockerfile
    DockerTag: jobs
  Properties:
    Events:
      SQSJobs:
        Type: SQS
        Properties:
          Queue: !GetAtt JobsQueue.Arn
          BatchSize: 1
          FunctionResponseTypes:
            - ReportBatchItemFailures
    ImageConfig:
      Command: ["config/environment.Lambdakiq.cmd"]
    MemorySize: 1792
    PackageType: Image
    Policies:
      - Version: "2012-10-17"
        Statement:
          - Effect: Allow
            Action:
              - sqs:*
            Resource:
              - !Sub arn:aws:sqs:${AWS::Region}:${AWS::AccountId}:${JobsQueue.QueueName}
    Timeout: 300

Here are some key aspects of our JobsLambda resource above:

  • We use the ImageConfig.Command to load your Rails env and invoke the Lambdakiq.cmd which calls the Lambdakiq.handler on your behalf.
  • The Events property uses the SQS Type.
  • The BatchSize can be any number you like. Less means more Lambda concurrency, more means some jobs could take longer. The jobs function Timeout must be lower than the JobsQueue's VisibilityTimeout property. When the batch size is one, the queue's visibility is generally one second more.
  • You must use ReportBatchItemFailures response types. Lambdakiq assumes we are reporting batch item failures. This is a new feature of SQS introduced in November 2021.
  • The Metadata's Docker properties must be the same as our web function except for the DockerTag. This is needed for the image to be shared. This works around a known SAM issue vs using the ImageConfig property.

🎉 Deploy your application and have fun with ActiveJob on SQS & Lambda.

Configuration

Most general Lambdakiq configuration options are exposed via the Rails standard configuration method.

Rails Configs

config.lambdakiq
  • max_retries= - Retries for all jobs. Default is the Lambdakiq maximum of 12.
  • metrics_namespace= - The CloudWatch Embedded Metrics namespace. Default is Lambdakiq.
  • metrics_logger= - Set to the Rails logger which is STDOUT via Lamby/Lambda.

ActiveJob Configs

You can also set configuration options on a per job basis using the lambdakiq_options method.

class OrderProcessorJob < ApplicationJob
  lambdakiq_options retry: 2
end
  • retry - Overrides the default Lambdakiq max_retries for this one job.

Observability with CloudWatch

Get ready to gain way more insights into your ActiveJobs using AWS' CloudWatch service. Every AWS service, including SQS & Lambda, publishes detailed CloudWatch Metrics. This gem leverages CloudWatch Embedded Metrics to add detailed ActiveJob metrics to that system. You can mix and match these data points to build your own CloudWatch Dashboards. If needed, any combination can be used to trigger CloudWatch Alarms. Much like Sumo Logic, you can search & query for data using CloudWatch Logs Insights.

CloudWatch Dashboard

Metrics are published under the Lambdakiq namespace. This is configurable using config.lambdakiq.metrics_namespace but should not be needed since all metrics are published using these three dimensions which allow you to easily segment metrics/dashboards to a specific application.

Metric Dimensions

  • AppName - This is the name of your Rails application. Ex: MyApp
  • JobEvent - Name of the ActiveSupport Notification. Ex: *.active_job.
  • JobName - The class name of the ActiveSupport job. Ex: NotificationJob

ActiveJob Event Names

For reference, here are the JobEvent names published by ActiveSupport. A few of these are instrumented by Lambdakiq since we use custom retry logic like Sidekiq. These event/metrics are found in the Rails application CloudWatch logs because they publish/enqueue jobs.

  • enqueue.active_job
  • enqueue_at.active_job

While these event/metrics can be found in the jobs function's log.

  • perform_start.active_job
  • perform.active_job
  • enqueue_retry.active_job
  • retry_stopped.active_job

Metric Properties

These are the properties published with each metric. Remember, properties can not be used as metric data in charts but can be searched using CloudWatch Logs Insights.

  • JobId - ActiveJob Unique ID. Ex: 9f3b6977-6afc-4769-aed6-bab1ad9a0df5
  • QueueName - SQS Queue Name. Ex: myapp-JobsQueue-14F18LG6XFUW5.fifo
  • MessageId - SQS Message ID. Ex: 5653246d-dc5e-4c95-9583-b6b83ec78602
  • ExceptionName - Class name of error raised. Present in perform and retry events.
  • EnqueuedAt - When ActiveJob enqueued the message. Ex: 2021-01-14T01:43:38Z
  • Executions - The number of current executions. Counts from 1 and up.
  • JobArg#{n} - Enumerated serialized arguments.

Metric Data

And finally, here are the metrics which each dimension can chart using CloudWatch Metrics & Dashboards.

  • Duration - Of the job event in milliseconds.
  • Count - Of the event.
  • ExceptionCount - Of the event. Useful with ExceptionName.

CloudWatch Dashboard Examples

Please share how you are using CloudWatch to monitor and/or alert on your ActiveJobs with Lambdakiq!

💬 #3

Common Questions

Are Scheduled Jobs Supported? - No. If you need a scheduled job please use the SAM Schedule event source which invokes your function with an Eventbridege AWS::Events::Rule.

Are FIFO Queues Supported? - Yes. When you create your AWS::SQS::Queue resources you can set the FifoQueue property to true. Remember that both your jobs queue and the redrive queue must be the same. When using FIFO we:

  • Simulate delay_seconds for ActiveJob's wait by using visibility timeouts under the hood. We still cap it to non-FIFO's 15 minutes.
  • Set both the messages message_group_id and message_deduplication_id to the unique job id provided by ActiveJob.

Can I Use Multiple Queues? - Yes. Nothing is stopping you from creating any number of queues and/or functions to process them. Your subclasses can use ActiveJob's queue_as method as needed. This is an easy way to handle job priorities too.

class SomeLowPriorityJob < ApplicationJob
  queue_as ENV['BULK_QUEUE_NAME']
end

What Is The Max Message Size? - 256KB. ActiveJob messages should be small however since Rails uses the GlobalID gem to avoid marshaling large data structures to jobs.

Contributing

After checking out the repo, run:

$ ./bin/bootstrap
$ ./bin/setup
$ ./bin/test

Bug reports and pull requests are welcome on GitHub at https://github.com/rails-lambda/lambdakiq. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the Contributor Covenant code of conduct.

Code of Conduct

Everyone interacting in the Lambdakiq project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the code of conduct.

More Repositories

1

lamby

Simple Rails & AWS Lambda Integration 🐑🛤
Ruby
504
star
2

secondbase

Seamless second database integration for Rails.
Ruby
219
star
3

strainer

Run isolated cookbook tests against your chef repository with Strainer.
Ruby
112
star
4

activerecord-colored_log_subscriber

Colorized SQL Logging Backport for ActiveRecord. See http://git.io/vmlOb
Ruby
92
star
5

activerecord-aurora-serverless-adapter

ActiveRecord Adapter for Amazon Aurora Serverless
Ruby
66
star
6

actionpack-cloudflare

Allow Rails request.remote_ip to defer to CloudFlare's connecting IP.
Ruby
51
star
7

crypteia

Rust Lambda Extension for any Runtime/Container to preload SSM Parameters as 🔐 Secure Environment Variables!
Shell
41
star
8

ruby-vips-lambda

AWS Lambda Layer for Ruby Libvips Gem
Dockerfile
38
star
9

activerecord-collection_cache_key

A Backport of Rails 5's collection cache keys to AR 3 and 4
Ruby
38
star
10

format_for_extensions

Extends ActiveRecord validates_format_of validations with reusable and customizable validation methods.
Ruby
34
star
11

central_log_viewer

Web based log viewer for the Central Logger
Ruby
32
star
12

lamby-cookiecutter

AWS SAM Cookiecutter to Quick Start Rails & Lambda 🐑🛤
HTML
27
star
13

mysql2-lambda

Precompiled Mysql2 Gem for AWS Lambda
Dockerfile
23
star
14

lambda_punch

Asynchronous background job processing for AWS Lambda with Ruby using Lambda Extensions. Inspired by the SuckerPunch gem but specifically tooled to work with Lambda's invoke model.
Ruby
19
star
15

cookiecutter-ruby-workshop

Cookiecutter Ruby - Microservice Workshop
18
star
16

webpack-react-graph

A webpack plugin that generates a graph visualization of a React component tree
JavaScript
16
star
17

signalerjs

JavaScript A/B testing feature flag library
JavaScript
14
star
18

actionpack-cloudfront

Configure ActionDispatch::RemoteIp trusted proxies for Amazon CloudFront.
Ruby
14
star
19

lamby-site

Simple Rails & AWS Lambda Integration 🚂🐑 (PRODUCT SITE)
JavaScript
13
star
20

lambdipy

A tool for building and packaging python packages for AWS Lambda.
Python
13
star
21

nagios-nrpe-check_glusterfs

Fork of Mark Ruys' check_glusterfs from http://exchange.nagios.org/directory/Plugins/System-Metrics/File-System/GlusterFS-checks/details
13
star
22

docker-rails-lambda

A simple Rails Lambda Project on Docker to test Mac filesystems (https://github.com/docker/roadmap/issues/7) benchmarks for the Docker team.
Ruby
11
star
23

ft2-ruby

Freetype2 ruby bindings
C
10
star
24

lambda-python-nltk-layer

Lambda layer to enable using famous NLTK python package with AWS lambda
Shell
10
star
25

codespaces-features

Public Codespaces Scripts/Features
Shell
9
star
26

lamby-rds-proxy

🦎♻️ Simple RDS Proxy Tutorial for Rails & Lambda
TypeScript
8
star
27

aws-embedded-metrics-customink

Amazon CloudWatch Embedded Metric Format Client Library for Ruby.
Ruby
8
star
28

sass_paths

Helper methods to append directories to the SASS_PATH ENV variable
Ruby
7
star
29

signalerjs-react

signalerjs React component for A/B testing
JavaScript
6
star
30

cookiecutter-ruby

Demo AWS SAM Lambda Cookiecutter Ruby Project
Python
6
star
31

capistrano-rollbar-sourcemaps

Uploads sourcemaps to Rollbar as a part of the Capistrano deploy process
Ruby
5
star
32

vertex_client

🧮 A ruby gem to interact with the Vertex Cloud API, which calculates sales tax.
Ruby
5
star
33

astro-devcontainer-example

An example project of how to use local devcontainers with the Astronomer Astro platform
Python
5
star
34

rubyconf5k_2015_results

Results for the 2015 RubyConf 5k in San Antonio, TX
4
star
35

is-it-up

A Ruby gem for adding a simple endpoint to see if your application "is up”.
Ruby
4
star
36

navigation_builder

Just like a Rails FormBuilder, but for Navigation
Ruby
4
star
37

gigo

Garbage in, garbage out. Fix ruby encoded strings at all costs.
Ruby
4
star
38

barcode_input

A Javascript handler for barcode scanner input
CoffeeScript
3
star
39

moxa_11x0

This is an updated driver for the Moxa USB to Serial 11x0 family adapters that runs on Linux kernel 2.6.32 (x86 or x64).
C
3
star
40

subexec-notifications

Instrumentation for Subexec commands using ActiveSupport::Notifications
Ruby
3
star
41

firstgiving_ruby

FirstGiving Ruby Client. Open Source!.
Ruby
2
star
42

nagios-check_s3_LastModified

Checks to see when an object in was last modified, and alerts based on thresholds you set.
Shell
2
star
43

customink.github.io

🐙 📒 CustomInk Technology Blog
HTML
2
star
44

greenscreenapp

A running version of GreenScreen
JavaScript
2
star
45

rolling_travis_builds

Rolling TravisCI Pro Builds - GitHub Webhook Template Application
Ruby
2
star
46

jquery-datalink

Fork of older version of git://github.com/jquery/jquery-datalink.git
JavaScript
2
star
47

homebrew-openssl-1.0

HomeBrew Tap for OpenSSL 1.0
Ruby
2
star
48

lambda_cable

Serverless WebSockets for Rails
Ruby
2
star
49

lamby-vpc

🦾🌎 Simple VPC for RDS Proxy Tutorial with Rails & Lambda
Shell
2
star
50

is_it_ready

Rails Engine for verifying whether applications are able to serve traffic
Ruby
2
star
51

dnd-demo

Docker in Docker Failure Demo
2
star
52

easy_office_map

Open source office map app created during Inkovate 2016 - CustomInk's internal hack-a-thon.
JavaScript
1
star
53

stuffed_bunny

Provides stubbing of the Bunny gem
Ruby
1
star
54

action_parameter_cache

1
star
55

pear-zipcodes-api

HTML
1
star
56

code-challenge

Represent code challenge
JavaScript
1
star
57

lambda-node-canvas-layer

Build and deploy an AWS Lambda layer for using node-canvas
Shell
1
star
58

gigo-activerecord

GIGO for ActiveRecord
Ruby
1
star
59

nagios-check_sftp_file_exist

A nagios check script that tests for the existence of a file on an SFTP server.
Shell
1
star
60

rubyconf5k_2014_results

Results for the 2014 Rubyconf 5k in San Diego
1
star
61

.github

Default Repository to hold the community health guidelines & template files
1
star
62

yaml-data

Safely read CloudFormation YAML data.
JavaScript
1
star
63

minitest-pngdiff

Minitest assertions to test for PNG differences
Ruby
1
star
64

aws-lambda-nodejs-runtime-interface-client-prebuilt

Dockerfile
1
star
65

frontend-gh-actions

Github actions by the frontend team
JavaScript
1
star
66

jekyll_hello_world

A Jekyll hello world for tinkering in AWS
Ruby
1
star