├── .devcontainer
├── devcontainer.json
├── postAttach.sh
└── postCreate.sh
├── .github
└── workflows
│ └── deploy.yml
├── .gitignore
├── README.md
├── babel.config.js
├── blog
├── 2022-12-19-welcome-to-lamby-v4.mdx
├── 2023-06-03-tailscale-extension-for-lambda-containers.mdx
├── 2023-06-17-the-elusive-lambda-console-a-specification-proposal.mdx
├── 2023-07-16-goodbye-cold-starts-hello-proactive-initilizations.mdx
├── authors.yml
└── youtube.css
├── docs
├── activejob.mdx
├── anatomy.mdx
├── assets.mdx
├── cold-starts.mdx
├── cpu-architecture.mdx
├── custom-domain.mdx
├── database.mdx
├── environment.mdx
├── observability.mdx
├── quick-start.mdx
├── running-tasks.mdx
└── webservers.mdx
├── docusaurus.config.js
├── package-lock.json
├── package.json
├── sidebars.js
├── src
├── components
│ ├── DocLink.js
│ └── HomepageFeatures
│ │ ├── index.js
│ │ └── styles.module.css
├── css
│ └── custom.css
└── pages
│ ├── index.js
│ ├── index.module.css
│ └── markdown-page.md
└── static
├── .nojekyll
├── CNAME
└── img
├── blog
├── console
│ └── header.png
├── proactive-init
│ └── lamby-cloud-watch-metrics-cold-start-v-proactive-init-dark.png
└── tailscale
│ ├── header.png
│ ├── live-development-proxy-detail.png
│ └── live-development-proxy-overview.png
├── docs
├── aws-api-gateway-icon.png
├── aws-elb-icon.png
├── aws_sam_introduction.png
├── circle-ci-trigger-workflow-dark.png
├── circle-ci-trigger-workflow-light.png
├── cold-start-cloudwatch-insights-percentiles-dark.png
├── cold-start-cloudwatch-insights-percentiles.png
├── cold-start-concurrency-dark.png
├── cold-start-concurrency-vs-spilled-dark.png
├── cold-start-concurrency-vs-spilled.png
├── cold-start-concurrency.png
├── devcontainer-console-dark.png
├── devcontainer-console-light.png
├── devcontainer-open-dark.png
├── devcontainer-open-light.png
├── github-actions-deploy.png
├── github-white.png
├── lambda-console-cli-dark.png
├── lambda-console-cli-light.png
├── lambdakiq.png
├── lambdapunch.png
├── lamby-arch-hero.png
├── lamby-cloud-watch-metrics-cold-start-v-proactive-init-dark.png
├── lamby-cloud-watch-metrics-cold-start-v-proactive-init-light.png
├── lamby-fullstack-serverless.png
├── lamby-rails.png
├── lamby-small.png
├── lamby.png
├── tailwindcss-dark.png
├── tailwindcss-light.png
├── you-are-on-rails-and-lambda-dark.png
└── you-are-on-rails-and-lambda-light.png
├── favicon.ico
├── lamby-logo-orig.png
├── lamby-logo-small.png
├── lamby-rails-arch-dark.png
├── lamby-rails-arch.png
├── lamby-rails-containers.jpg
└── lamby-rails-dark.jpg
/.devcontainer/devcontainer.json:
--------------------------------------------------------------------------------
1 | {
2 | "image": "mcr.microsoft.com/devcontainers/javascript-node:18",
3 | "customizations": {
4 | "codespaces": {
5 | "openFiles": [
6 | "README.md"
7 | ]
8 | },
9 | "vscode": {
10 | "extensions": [
11 | "unifiedjs.vscode-mdx"
12 | ]
13 | }
14 | },
15 | "features": {
16 | "ghcr.io/devcontainers/features/common-utils": {},
17 | "ghcr.io/devcontainers/features/sshd:latest": {}
18 | },
19 | "forwardPorts": [3080],
20 | "portsAttributes": {
21 | "3080": {
22 | "label": "Site",
23 | "onAutoForward": "openPreview"
24 | }
25 | },
26 | "postCreateCommand": ".devcontainer/postCreate.sh",
27 | "postAttachCommand": ".devcontainer/postAttach.sh"
28 | }
29 |
--------------------------------------------------------------------------------
/.devcontainer/postAttach.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | set -e
3 |
4 | npm install
5 | npm start
6 |
--------------------------------------------------------------------------------
/.devcontainer/postCreate.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | set -e
3 |
4 | git config --global --add safe.directory /workspaces/lamby-site
5 |
--------------------------------------------------------------------------------
/.github/workflows/deploy.yml:
--------------------------------------------------------------------------------
1 | name: Build & Deploy
2 | on:
3 | push:
4 | branches:
5 | - master
6 | pull_request:
7 | jobs:
8 | deploy:
9 | runs-on: ubuntu-latest
10 | permissions:
11 | contents: write
12 | steps:
13 | - uses: actions/checkout@v3
14 | - run: npm install
15 | - run: npm run build
16 | - name: Deploy Site
17 | uses: peaceiris/actions-gh-pages@v3
18 | if: ${{ github.ref == 'refs/heads/master' }}
19 | with:
20 | github_token: ${{ secrets.GITHUB_TOKEN }}
21 | publish_dir: ./build
22 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Dependencies
2 | /node_modules
3 |
4 | # Production
5 | /build
6 |
7 | # Generated files
8 | .docusaurus
9 | .cache-loader
10 |
11 | # Misc
12 | .DS_Store
13 | .env.local
14 | .env.development.local
15 | .env.test.local
16 | .env.production.local
17 | .vscode
18 |
19 | npm-debug.log*
20 | yarn-debug.log*
21 | yarn-error.log*
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Lamby Site
2 |
3 |
4 |
5 | - Documentation and blog site for Lamby
6 | - Uses Docusaurus as our static site generator.
7 | - Leverages development containers & Codespaces.
8 | - Easily contribute by opening a pull request.
9 |
10 | **[Lamby: Simple Rails & AWS Lambda Integration using Rack.](https://lamby.cloud)**
11 |
12 | ## Contributing
13 |
14 | This project is built for [GitHub Codespcaes](https://github.com/features/codespaces) using the [Development Container](https://containers.dev) specification. Once you have the repo cloned and setup with a dev container using either Codespaces or [VS Code](#using-vs-code), run the following commands. This will install packages and run tests.
15 |
16 | ```shell
17 | npm start
18 | ```
19 |
20 | #### Using VS Code
21 |
22 | If you have the [Visual Studio Code Dev Container](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers) extension installed you can easily clone this repo locally, use the "Open Folder in Container..." command. This allows you to use the integrated terminal for the commands above.
23 |
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: [require.resolve('@docusaurus/core/lib/babel/preset')],
3 | };
4 |
--------------------------------------------------------------------------------
/blog/2022-12-19-welcome-to-lamby-v4.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | slug: welcome-to-lamby-v4
3 | title: Welcome Lamby v4!
4 | authors: [kcollins]
5 | tags: [rails, lambda, containers]
6 | ---
7 |
8 | import DocLink from "../src/components/DocLink.js";
9 | import ThemedImage from "@theme/ThemedImage";
10 | import useBaseUrl from "@docusaurus/useBaseUrl";
11 |
12 | I am incredibly happy to announcy Lamby v4 and a major update to our documentation website. Huge shout out to [Docusaurus](https://docusaurus.io) which has made in my opinion the best content-driven static site generator for open-source projects like our Lamby community.
13 |
14 |
15 |
16 |
23 |
24 | So what is new and will v4 break anything? Lots! Mostly new ways of thinking around the same basic architecture. Nothing should break either. Lamby v4's semver change is mostly marketing driven. Here is a short list of what is new.
25 |
26 | ## Updated Starter
27 |
28 | Want to see all this new stuff in action? Use our guide to deploy a new Rails application to AWS Lambda in 5min ⏱️.
29 |
30 | ## Bring Your Own Containers
31 |
32 | Lamby still works with the Zip packaging format, but all documentation on how to use it has been removed. Containers are here to stay and their value goes way past a simple packaging format.
33 |
34 | ```mermaid
35 | %%{init:{'flowchart':{'nodeSpacing': 20, 'rankSpacing': 20}}}%%
36 | flowchart LR
37 | %% Objects
38 | src-furl(Lambda Function URLs)
39 | src-apih(API Gateway HTTP API)
40 | src-apir(API Gateway REST API)
41 | src-alb(Application Load Balancer)
42 | invoke[/invoke/]
43 | lambda[Lambda Function]
44 | subgraph container["Container Image"]
45 | direction LR
46 | ric[RIC -> config/env.Lamby.cmd]:::rics
47 | app[Event -> Rack -> Rails::App]:::pink
48 | os[Operatring System & Packages]:::desc
49 | end
50 | %% Flow
51 | src-furl --> |Event| invoke
52 | src-apih --> |Event v1 or v2| invoke
53 | src-apir --> |Event| invoke
54 | src-alb --> |Event| invoke
55 | invoke --> lambda
56 | lambda --> ric
57 | %% Styles
58 | classDef node fill:#a99ff0,stroke:#fff,stroke-width:4px,color:#000;
59 | classDef pink fill:#fe4f8b,stroke:#fff,stroke-width:4px,color:#fff;
60 | classDef orange fill:#ed8235,stroke:#fff,stroke-width:4px,color:#fff;
61 | classDef cont fill:#c6fffd,stroke:#70d6d2,stroke-width:4px,color:black,font-size:12px;
62 | classDef rics fill:#a99ff0,stroke:#fff,stroke-width:4px,color:#000;
63 | classDef desc fill:white,stroke:#ccc,stroke-width:2px,color:black;
64 | %% ,font-size:12px
65 | class src-apir,src-apih pink
66 | class src-alb orange
67 | class container cont
68 | class ric rics
69 | ```
70 |
71 | We now encourage bringing your own containers by using Lambda's Runtime Interface Client (RIC). The RIC allows us to use Docker's `CMD` to load Rails and invoke a function. In this case we are loading our Rails application through its config/environment.rb file (.rb extension is implied) and once that is done, calling the new `Lamby.cmd` as the Lambda handler. No more `app.rb`
72 | file needed!
73 |
74 | ```docker title="Dockerfile"
75 | FROM ruby:3.2-bullseye
76 | RUN gem install 'aws_lambda_ric'
77 | ENTRYPOINT [ "/usr/local/bundle/bin/aws_lambda_ric" ]
78 | CMD ["config/environment.Lamby.cmd"]
79 | ```
80 |
81 | ## Secrets with Crypteia
82 |
83 | The [Crypteia](https://github.com/rails-lambda/crypteia) package is Rust Lambda Extension for any Runtime/Container to preload SSM Parameters as secure environment variables. It takes advantages of `LD_PRELOAD` to seamlessly fetch values from SSM when a process starts and then injects them as natively accesible Ruby `ENV` variables. Our guide's cookiecutter includes Crypteia already for you via a Docker `COPY` command into the Lambda Extension `/opt` directory.
84 |
85 | ```docker title="Dockerfile"
86 | FROM ruby:3.2-bullseye
87 | # highlight-next-line
88 | COPY --from=ghcr.io/rails-lambda/crypteia-extension-debian:1 /opt /opt
89 | ```
90 |
91 | Usage is simply done by adding variables to your SAM template and accessing the values fetched from SSM like any other environment variable. Please read the Crypteia's [documentation](https://github.com/rails-lambda/crypteia) for full details.
92 |
93 | ```title="template.yaml"
94 | Globals:
95 | Environment:
96 | Variables:
97 | SECRET: x-crypteia-ssm:/myapp/SECRET
98 | ```
99 |
100 | ```ruby
101 | ENV['SECRET'] # 1A2B3C4D5E6F
102 | ```
103 |
104 | ## Development Containers
105 |
106 | Described in the guide, our Lamby starter makes use of the [Development Container](https://containers.dev) specification via a [`.devcontainer`](https://github.com/rails-lambda/lamby-cookiecutter/tree/master/%7B%7Bcookiecutter.project_name%7D%7D/.devcontainer) directory. Commonly used with Codespaces, dev containers can be used locally with any editor.
107 |
108 | Our dev container's `Dockerfile` uses the same base image as the one at the root of your project. This helps ensure your development experience, like installing system dependencies and Ruby gems with native extensions, aligns with the same process as your production image.
109 |
110 | We also leverage the devcontainer's `dockerComposeFile` capability to include a MySQL service as well. The Lamby starter also includes a range of [devcontainer features](https://containers.dev/features) which are installed within the Ubuntu development image. For example, Node, Docker in Docker, SSH, and the AWS CLI & SAM CLI.
111 |
--------------------------------------------------------------------------------
/blog/2023-06-03-tailscale-extension-for-lambda-containers.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | slug: tailscale-extension-for-lambda-containers
3 | title: Using Tailscale on Lambda for a Live Development Proxy
4 | authors: [kcollins]
5 | tags: [tailscale, websockets, lambda, extension, container]
6 | image: https://lamby.cloud/img/blog/tailscale/header.png
7 | description: Tailscale makes networking easy. Like really easy. It shines in situations where private networks do not allow inbound connections.
8 | ---
9 |
10 | import styles from "./youtube.css";
11 |
12 | 
13 |
14 | ⚠️ DISCLAIMER: In no way am I advocating for the use of live proxies as a normal way to develop against cloud resources. However in some edge cases, such as developing a new system, live dev proxies or the general use of Tailscale in Lambda could be useful.
15 |
16 |
17 |
18 | ## 🐋 Tailscale on Lambda
19 |
20 | [Tailscale](https://tailscale.com) makes networking easy. Like really easy. It shines in situations where private networks do not allow inbound connections. Tailscale can connect your devices and development environments for easy access to remote resources, or allow those remote systems to access your home or office network devices.
21 |
22 | A few years ago Corey Quinn wrote a Tailscale [Lambda Extension](https://www.lastweekinaws.com/blog/corey-writes-open-source-code-for-lambda-and-tailscale/). It is great and helped a lot of folks. Today, I'd like to share a new project based on Corey's work that makes it even easier to use Tailscale in Lambda Container. Check it out here.
23 |
24 | **[🔗 Tailscale Lambda Extension for Containers](https://github.com/rails-lambda/tailscale-extension)** on GitHub 🐙
25 |
26 | This new version tries to improve upon Corey's work. Initialization is now stable, there are more configuration options, and we even have multi-platform Docker container packages for both `x86_64` and `arm64`. We even have Amazon Linux 2 and Debian/Ubuntu variants. Installation is really easy, simply add one line to your Dockerfile. For example:
27 |
28 | ```dockerfile
29 | FROM public.ecr.aws/lambda/ruby:3.2
30 | RUN yum install -y curl
31 | COPY --from=ghcr.io/rails-lambda/tailscale-extension-amzn:1 /opt /opt
32 | ```
33 |
34 | Once your container starts, taking to any device within your tailnet can be done by using the local [SOCKS5](https://en.wikipedia.org/wiki/SOCKS) proxy. In the example below, we are using Ruby's [socksify](https://github.com/astro/socksify-ruby) gem.
35 |
36 | ```ruby
37 | require 'socksify/http'
38 | Net::HTTP.socks_proxy('localhost', 1055).start(...) do |http|
39 | # your http code here...
40 | end
41 | ```
42 |
43 | ## 🔌 ActionCable on Lambda
44 |
45 | How did I use Tailscale for the [Rails on Lambda](https://lamby.cloud) work? A few months ago, I [started work](https://twitter.com/metaskills/status/1647714842550185985) on the last critical part of the Rails ecosystem which did not work on Lambda... [ActionCable](https://guides.rubyonrails.org/action_cable_overview.html) & WebSockets. Specifically, I wanted [Hotwire](https://hotwired.dev) to work.
46 |
47 | So far, everything is [working great](https://twitter.com/metaskills/status/1651067256242151424) with our new LambdaCable gem. Eventually it will be a drop-in adapter for ActionCable and join the ranks of other popular alternatives like [AnyCable](https://anycable.io). To bring the project to completion faster, I needed feedback loops that were much faster than deploying code to the cloud. I needed a development proxy! One where my Rails application would receive events from both Lambda's Function URLs and the WebSocket events from API Gateway. Illustrated below with a demo video.
48 |
49 | 
50 |
51 |
52 |
61 |
62 |
63 | If you are curious to learn more about how Rails & Lambda work together, check out our [Lamby](https://lamby.cloud) project. The architecture of Lambda Containers works so well with Rails since our framework distills everything from HTTP, Jobs, Events, & WebSocket connections down to Docker's `CMD` interface. The architecture above at the proxy layer was easy to build and connect up to our single delegate function, `Lamby.cmd`. Shown below:
64 |
65 | 
66 |
67 | For our Rails application on Lambda, here are the changes we made to leverage this. All outlined in our [WebSockets Demo Pull Request](https://github.com/rails-lambda/websocket-demo/pull/4).
68 |
69 | - Created a `.localdev` folder. Added a copy of our SAM template.yaml for all AWS Resources.
70 | - Made a simple `.localdev/Dockerfile` that included the Tailscale Extension along with basic proxy code.
71 | - Leveraged Lamby's [Local Development Proxy Sever](https://github.com/rails-lambda/lamby/pull/164).
72 | - Ensured our Devcontainers exposed port 3000 to all local network devices so Tailscale could detect the service.
73 |
74 | I hope you find reasons to learn more about Tailscale and how using a SOCKS5 proxy from Lambda could help your development or production needs. More so, I hope you like the new Lambda Extension project of ours making it easy for containerized applications to use. Drop us a comment if you do.
75 |
76 | **[🔗 Tailscale Lambda Extension for Containers](https://github.com/rails-lambda/tailscale-extension)** on GitHub 🐙
77 |
--------------------------------------------------------------------------------
/blog/2023-06-17-the-elusive-lambda-console-a-specification-proposal.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | slug: the-elusive-lambda-console-a-specification-proposal
3 | title: The Elusive Lambda Console; A Specification Proposal.
4 | authors: [kcollins]
5 | tags: [rails, lambda, console, specification, runner, tasks, interaction]
6 | image: img/blog/console/header.png
7 | ---
8 |
9 | import Header from '@site/static/img/blog/console/header.png';
10 | import ThemedImage from "@theme/ThemedImage";
11 | import useBaseUrl from "@docusaurus/useBaseUrl";
12 |
13 |
14 |
15 |
16 |
17 | After years of smashing Cloud & Rails together, I've come up with an idea. Better than an idea, a working specification! One where us [Rails & Lambda](https://lamby.cloud) enthusiasts can once again "console into" our "servers" and execute CLI tasks like migrations or interact via our beloved IRB friend, the Rails console. Today, I would like to present, the [Lambda Console](https://github.com/rails-lambda/lambda-console) project. An open specification proposal for any AWS Lambda runtime to adopt.
18 |
19 |
20 |
21 |
22 |
29 |
30 |
31 | ## Lambda Console
32 |
33 | ```shell
34 | npm install -g lambda-console-cli
35 | ```
36 |
37 | The Lambda Console is a CLI written in Node.js that will interactively create an AWS SDK session for you to invoke your Lambda functions with two types of modes.
38 |
39 | 1. CLI Runner
40 | 2. Interactive Commands
41 |
42 | Think of the CLI Runner as a bash prompt. You can run any process command or interact with the filesystem or environment. For Rails users, running rake tasks or DB migrations. These tasks assume the Lambda task root as the present working directory.
43 |
44 | Interactive commands however are evaluated in the context of your running application. For Ruby and Rails applications, this simulates IRB (Interactive Ruby Shell). For [Lamby](https://lamby.cloud) users, this mode simulates the Rails console. Making it easy for users to query their DB or poke their models and code.
45 |
46 | ## The Proposal
47 |
48 | There is nothing about the [Lambda Console](https://github.com/rails-lambda/lambda-console) that is coupled to Ruby or Rails. The idea is simple, as a Lambda community, could we do the following?
49 |
50 | 1. Finalize a Lambda Console request/response specification.
51 | 2. Create more runtime-specific language implementations.
52 | 2. Build an amazing CLI client for any runtime.
53 |
54 | Here is what we have today. The request specification, a simple [event structure](https://github.com/rails-lambda/lambda-console#event-structure) that is only a few dozen lines of JSON schema.
55 |
56 | ```json
57 | { "X_LAMBDA_CONSOLE": { "run": "cat /etc/os-release" } }
58 | ```
59 |
60 | ```json
61 | { "X_LAMBDA_CONSOLE": { "interact": "User.find(1)" } }
62 | ```
63 |
64 | Any Lambda runtime code or framework could implement the handling of these event in their own language-specific pakages. You can find the Ruby implementation of these in the Lambda Console's first reference implementations.
65 |
66 | * Ruby: The [lambda-console-ruby](https://github.com/rails-lambda/lambda-console-ruby) gem for any Ruby Lambda.
67 | * Rails: Integrated into the [Lamby](https://github.com/rails-lambda/lamby) v5.0.0 for Rails on Lambda.
68 |
69 | ## The Possibilities
70 |
71 | What I really want is an amazing CLI client. The current Lambda Console CLI was hacked together in a few days using some amazing Node.js tools that make building interactive CLIs so so easy. But I've never done this before. If this type of tooling sounds interesting to you and you like Node.js, let me know! It would be amazing to see implementation packages for these for Node, PHP, Python, and other frameworks using these languages. Here are some ideas on where I could see this going.
72 |
73 | **Live STDOUT & STDERR:** We could take advantage of Lambda's new [Response Streaming](https://aws.amazon.com/blogs/compute/introducing-aws-lambda-response-streaming/) and send output buffers as they happen.
74 |
75 | **Pseudo TTY:** Is there a way to better simulate a real TTY session? Could this even include ANSI colors?
76 |
77 | **Quality of Life Improvements:** Everything from, Allowing the CLI tool to switch modes without restarting it; Creating a command buffer to up arrow navigate history; Prettier UI.
78 |
79 | **Formal Response JSON Schema:** As the features grow, should the response JSON be standardized? For example, if the client wanted to syntax highlight interactive language commands, how would it know what language was being used? We could have a `X_LAMBDA_CONSOLE_LANG` response header.
80 |
81 | What else would you like to see in a Lambda Console client?
82 |
83 |
--------------------------------------------------------------------------------
/blog/2023-07-16-goodbye-cold-starts-hello-proactive-initilizations.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: Goodbye Cold Starts, Hello Proactive Initialization
3 | authors: [kcollins]
4 | tags: [rails, lambda, cold-starts, initialization]
5 | image: img/blog/proactive-init/lamby-cloud-watch-metrics-cold-start-v-proactive-init-dark.png
6 | ---
7 |
8 | import ThemedImage from "@theme/ThemedImage";
9 | import useBaseUrl from "@docusaurus/useBaseUrl";
10 |
11 | As described in [AJ Stuyvenberg's](https://twitter.com/astuyve) post on the topic [Understanding AWS Lambda Proactive Initialization](https://aaronstuyvenberg.com/posts/understanding-proactive-initialization), AWS Lambda may have solved some of your cold start issues for you since March 2023. Stated in an excerpt [from AWS' docs](https://aaronstuyvenberg.com/posts/understanding-proactive-initialization):
12 |
13 | > For functions using unreserved (on-demand) concurrency, Lambda occasionally pre-initializes execution environments to reduce the number of cold start invocations. For example, Lambda might initialize a new execution environment to replace an execution environment that is about to be shut down. If a pre-initialized execution environment becomes available while Lambda is initializing a new execution environment to process an invocation, Lambda can use the pre-initialized execution environment.
14 |
15 |
16 |
17 | This means the [Monitoring with CloudWatch](#monitoring-with-cloudwatch) is just half the picture. But how much is your application potentially benefiting from proactive inits? Since [Lamby v5.1.0](https://github.com/rails-lambda/lamby/pull/169), you can now find out easily using CloudWatch Metrics. To turn metrics on, enable the config like so:
18 |
19 | ```rails title="config/environments/production.rb"
20 | config.lamby.cold_start_metrics = true
21 | ```
22 |
23 | Lamby will now publish [CloudWatch Embedded Metrics](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch_Embedded_Metric_Format.html) in the `Lamby` namespace with a custom dimension for each application's name. Captured metrics include counts for Cold Starts vs. Proactive Initializations. Here is an example running sum of 3 days of data for a large Rails application in the `us-east-1` region.
24 |
25 |
36 |
37 | This data shows the vast majority of your initialized Lambda Containers are proactively initialized. Hence, no cold starts are felt by end users or consumers of your function. If you need to customize the name of your Rails application in the CloudWatch Metrics dimension, you can do so using this config.
38 |
39 | ```rails title="config/environments/production.rb"
40 | config.lamby.metrics_app_name = 'MyServiceName'
41 | ```
42 |
--------------------------------------------------------------------------------
/blog/authors.yml:
--------------------------------------------------------------------------------
1 |
2 | kcollins:
3 | name: Ken Collins
4 | title: Principal Engineer & Cloud Architect
5 | url: https://dev.to/metaskills
6 | image_url: https://github.com/metaskills.png
7 |
--------------------------------------------------------------------------------
/blog/youtube.css:
--------------------------------------------------------------------------------
1 | .video-container {
2 | position: relative;
3 | padding-bottom: 56.25%;
4 | height: 0;
5 | margin-bottom: 2rem;
6 | }
7 | .video-container iframe {
8 | position: absolute;
9 | top: 0;
10 | left: 0;
11 | width: 100%;
12 | height: 100%;
13 | }
14 |
--------------------------------------------------------------------------------
/docs/activejob.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | id: activejob
3 | title: ActiveJob & Background Processing
4 | toc_max_heading_level: 2
5 | ---
6 |
7 | # ActiveJob & Background Processing
8 |
9 | import DocLink from "../src/components/DocLink.js";
10 |
11 | ## Lambdakiq
12 |
13 |
14 |
24 |
25 |
26 | Using ActiveJob on AWS Lambda is a reimagination of the problem for Rails. Instead of starting up long running process that polls for work, we instead use the event-driven architecture of AWS Lambda to our advantage using a gem named [Lambdakiq](https://github.com/rails-lambda/lambdakiq) which is mostly a drop-in replacement for [Sidekiq](https://github.com/mperham/sidekiq).
27 |
28 | It 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. Key Features:
29 |
30 | - Distinct web & jobs Lambda functions.
31 | - AWS fully managed polling. Event-driven.
32 | - Maximum 12 retries. Per job configurable.
33 | - Mirror Sidekiq's retry [backoff](https://github.com/mperham/sidekiq/wiki/Error-Handling#automatic-job-retry) timing.
34 | - Last retry is at 11 hours 30 minutes.
35 | - Supports ActiveJob's wait/delay. Up to 15 minutes.
36 | - Dead messages are stored for up to 14 days.
37 |
38 | Learn more on GitHub: https://github.com/rails-lambda/lambdakiq
39 |
40 | ## LambdaPunch
41 |
42 |
43 |
53 |
54 |
55 | You may need lightweight background job processing similiar to how [SuckerPunch](https://github.com/brandonhilkert/sucker_punch) gem works. The only way to do this for Lambda is to use the [LambdaPunnch](https://github.com/rails-lambda/lambda_punch) gem. LambdaPunch is a [Lambda Extensions](https://docs.aws.amazon.com/lambda/latest/dg/runtimes-extensions-api.html) that works with the Lambda invoke model. This solution is required if you are using New Relic as described in our guide.
56 |
57 | Learn more on GitHub: https://github.com/rails-lambda/lambda_punch
58 |
--------------------------------------------------------------------------------
/docs/anatomy.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | id: anatomy
3 | title: How Lamby Works
4 | toc_max_heading_level: 3
5 | ---
6 |
7 | import DocLink from "../src/components/DocLink.js";
8 | import ThemedImage from "@theme/ThemedImage";
9 | import useBaseUrl from "@docusaurus/useBaseUrl";
10 |
11 | # How Lamby Works
12 |
13 | The quickest way to see Lamby in action is to create a new Rails app via our cookiecutter project template using our guide. This guide will instead outline what is happening within that starter project allowing you to cherry-pick which files and/or practices from our [cookiecutter](https://github.com/rails-lambda/lamby-cookiecutter) project can be applied to your own application(s).
14 |
15 | :::note
16 | If you copy any template files without using the cookiecutter, remember to customize the `{% include ... %}` template sections with your own app name and remove the curly bracket sections like these `{{ "..." }}` from various string literals.
17 | :::
18 |
19 | ## Architecture
20 |
21 | Lamby is a Rack adapter that converts AWS Lambda integration events into native [Rack Environment](https://github.com/rack/rack/blob/master/SPEC.rdoc) objects which are sent directly to your application. Lamby can automatically do this when using either Lambda Function URLs, API Gateway HTTP API v1/v2 payloads, API Gateway REST API, or even Application Load Balancer (ALB) integrations.
22 |
23 | ```mermaid
24 | %%{init:{'flowchart':{'nodeSpacing': 20, 'rankSpacing': 20}}}%%
25 | flowchart LR
26 | %% Objects
27 | src-furl(Lambda Function URLs)
28 | src-apih(API Gateway HTTP API)
29 | src-apir(API Gateway REST API)
30 | src-alb(Application Load Balancer)
31 | invoke[/invoke/]
32 | lambda[Lambda Function]
33 | subgraph container["Container Image"]
34 | direction LR
35 | ric[RIC -> config/env.Lamby.cmd]:::rics
36 | app[Event -> Rack -> Rails::App]:::pink
37 | os[Operating System & Packages]:::desc
38 | end
39 | %% Flow
40 | src-furl --> |Event| invoke
41 | src-apih --> |Event v1 or v2| invoke
42 | src-apir --> |Event| invoke
43 | src-alb --> |Event| invoke
44 | invoke --> lambda
45 | lambda --> ric
46 | %% Styles
47 | classDef node fill:#a99ff0,stroke:#fff,stroke-width:4px,color:#000;
48 | classDef pink fill:#fe4f8b,stroke:#fff,stroke-width:4px,color:#fff;
49 | classDef orange fill:#ed8235,stroke:#fff,stroke-width:4px,color:#fff;
50 | classDef cont fill:#c6fffd,stroke:#70d6d2,stroke-width:4px,color:black,font-size:12px;
51 | classDef rics fill:#a99ff0,stroke:#fff,stroke-width:4px,color:#000;
52 | classDef desc fill:white,stroke:#ccc,stroke-width:2px,color:black;
53 | %% ,font-size:12px
54 | class src-apir,src-apih pink
55 | class src-alb orange
56 | class container cont
57 | class ric rics
58 | ```
59 |
60 | Since Rails applications are Rack applications, Lamby removes the need for a companion [Rack Web Server](https://github.com/rack/rack#supported-web-servers) like Passenger or Puma to be running within your container. Essentially AWS integrations become your web server and scaling is managed by the Lambda service spinning up new container instances, one for each request or down to zero if needed. Lambda instances live for several minutes or more. A small pool of concurrent fuctions can handle a large amount of traffic.
61 |
62 | ## Install Lamby
63 |
64 | Start by adding the Lamby gem to your `Gemfile`. It remains inert until it detects special environment variables present when run on AWS Lambda. When activated, it mostly does a few simple things like ensuring Rails logs to standard out.
65 |
66 | ```ruby
67 | gem 'lamby'
68 | ```
69 |
70 | ## Runtime Container
71 |
72 | You will need some [`Dockerfile`](https://github.com/rails-lambda/lamby-cookiecutter/blob/master/%7B%7Bcookiecutter.project_name%7D%7D/Dockerfile) to build your Lambda container image. Referencing architecture diagram above mentions something called a RIC (Rick). The RIC is short for the Lambda [Runtime Interface Client](https://github.com/aws/aws-lambda-ruby-runtime-interface-client). It is a small interface packaged as a Ruby gem that acts as the `ENTRYPOINT` for any [OCI](https://opencontainers.org) continer image to run on the AWS Lambda platform. Below you can see that we are using an [Official Ruby](https://hub.docker.com/_/ruby) Ubuntu variant base image, installing the RIC and setting it as the entrypoint.
73 |
74 | ```docker title="Dockerfile"
75 | FROM ruby:3.2-bullseye
76 |
77 | RUN gem install 'aws_lambda_ric'
78 | ENTRYPOINT [ "/usr/local/bundle/bin/aws_lambda_ric" ]
79 | CMD ["config/environment.Lamby.cmd"]
80 | ```
81 |
82 | The RIC allows us to use Docker's `CMD` to load Rails and invoke a function. In this case we are loading our Rails application through its `config/environment.rb` file (.rb extension is implied) and once that is done, calling the `Lamby.cmd` as the Lambda handler.
83 |
84 | :::note
85 | Our [cookiecutter](https://github.com/rails-lambda/lamby-cookiecutter) project defaults to building a Linux image targeting the `arm64` architecture vs the traditional `x86_64`. However, this is easily changed to accomodate your needs. Check out the section for more details.
86 | :::
87 |
88 | ## SAM CloudFormation File
89 |
90 | The [`template.yaml`](https://github.com/rails-lambda/lamby-cookiecutter/blob/master/%7B%7Bcookiecutter.project_name%7D%7D/template.yaml) file at the root of your project describes your [Serverless Application](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/what-is-sam.html). Don't worry, we have done some heavy lifting for you. Here is the [Serverless Function](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-resource-function.html) Resource we start you off with and a brief explanation:
91 |
92 | ```yaml title="template.yaml"
93 | RailsLambda:
94 | Type: AWS::Serverless::Function
95 | Metadata:
96 | DockerContext: .
97 | Dockerfile: Dockerfile
98 | DockerTag: web
99 | Properties:
100 | AutoPublishAlias: live
101 | FunctionUrlConfig:
102 | AuthType: NONE
103 | DeploymentPreference:
104 | Type: AllAtOnce
105 | MemorySize: 1792
106 | PackageType: Image
107 | Timeout: 30
108 | ```
109 |
110 | - Your Rails function will have a `MemorySize` of 1,792 MB of RAM and 1 vCPU. This is the sweet spot for Rails speed and cost optimization. Remember, you're not running a web server in a single function nor scaling by memory.
111 | - The `FunctionUrlConfig` has been configured to be a public HTTP proxy. You can change this to IAM authentication or swap out to other web server integrations like API Gateway if you need their features. Details in other guides.
112 | - The maximum amount of `Timeout` for an HTTP integration is 30 seconds.
113 |
114 |
119 |
120 | As your application grows you may end up adding Resources like EventBridge Rules, SQS, S3 Buckets, and IAM Policies. Please take some time to learn how SAM & CloudFormation work.
121 |
122 | - [What Is the AWS Serverless Application Model (AWS SAM)?](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/what-is-sam.html)
123 | - [Quick Intro & Tech Spec for SAM File](https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md)
124 | - [What is AWS CloudFormation?](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/Welcome.html)
125 |
126 | ## Development Container
127 |
128 | Described in the guide, our Lamby starter makes use of the [Development Container](https://containers.dev) specification via a [`.devcontainer`](https://github.com/rails-lambda/lamby-cookiecutter/tree/master/%7B%7Bcookiecutter.project_name%7D%7D/.devcontainer) directory. Commonly used with Codespaces, dev containers can be used locally with any editor.
129 |
130 | Our dev container's `Dockerfile` uses the same base image as the one at the root of your project. This helps ensure your development experience, like installing system dependencies and Ruby gems with native extensions, aligns with the same process as your production image.
131 |
132 | We also leverage the devcontainer's `dockerComposeFile` capability to include a MySQL service as well. The Lamby starter also includes a range of [devcontainer features](https://containers.dev/features) which are installed within the Ubuntu development image. For example, Node, Docker in Docker, SSH, and the AWS CLI & SAM CLI.
133 |
134 | :::note
135 | Technically you do not need to adopt these devcontainer patterns, but it is really nice to be able to use this container to ensure your CI/CD process is reproducable locally using VS Code or the [Dev Container CLI](https://github.com/devcontainers/cli). More details in the following CI/CD section.
136 | :::
137 |
138 | ## Deployment & CI/CD
139 |
140 | So how does that CloudFormation file and container image get created within AWS? We use the AWS SAM CLI's `build`, `package`, and `deploy` commands in a single [`bin/deploy`](https://github.com/rails-lambda/lamby-cookiecutter/blob/master/%7B%7Bcookiecutter.project_name%7D%7D/bin/deploy) file. This file also does the following. Feel free to customize your deploy files as needed:
141 |
142 | - Finds/Creates an ECR repository with the same name as your project.
143 | - Sets various ENV variables if not set already. For example, easy to deploy to multiple regions by setting `AWS_REGION`.
144 | - Install gems into local vendor/bundle for deployment via a Docker `COPY`.
145 |
146 | If you used our guide, you likely made your first deploy using VS Code's integrated terminal within the development container. This is critically important since your Ruby gems with native extensions are built within the context of the Ruby Ubuntu image being built and copied to ECR for Lambda to use.
147 |
148 | When automating deployments, the system must have permission to create the needed resources and IAM Roles with permission(s) for your application to work. Most hobby users have admin level access to their own AWS account. For more security minded folks, consider creating a [least privilege user](https://docs.aws.amazon.com/lambda/latest/dg/access-control-identity-based.html) for your deployments with [OpenID Connect](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_providers_create_oidc.html) identity providers. We found that the `AWSCodeDeployFullAccess` managed policy is often overlooked.
149 |
150 | ### CircleCI
151 |
152 | If `arm64` is your target platform in production, CircleCI make it easy to to do so using their [Arm Execution Environment](https://circleci.com/docs/using-arm/). Our starter includes a CircleCI `config.yml` file that runs tests on each commit or deploy by manually triggering a workflow. It even uses the [Devcontainer CLI](https://github.com/devcontainers/cli) to ensure your CI/CD matches your development experience. Changing between `arm64` and `x86_64` is described in our guide.
153 |
154 | - [Test & Deploy CircleCI Template](https://github.com/rails-lambda/lamby-cookiecutter/blob/master/%7B%7Bcookiecutter.project_name%7D%7D/.circleci/config.yml)
155 |
156 | Deploying requires manually triggering the workflow. Simply select a branch then click "Trigger Workflow" and pass a string parameter called "workflow" with a value of "deploy". Feel free to change this workflow to suite your needs.
157 |
158 |
165 |
166 | ### GitHub Actions
167 |
168 | You can automate both the test and deploy process using our provided GitHub Actions which also leverage the [Dev Container Build and Ruby CI](https://github.com/devcontainers/ci) project.
169 |
170 | - [Deploy GitHub Action Template](https://github.com/rails-lambda/lamby-cookiecutter/blob/master/%7B%7Bcookiecutter.project_name%7D%7D/.github/workflows/deploy.yml)
171 | - [Test GitHub Action Template](https://github.com/rails-lambda/lamby-cookiecutter/blob/master/%7B%7Bcookiecutter.project_name%7D%7D/.github/workflows/test.yml)
172 |
173 | 1. Within your project's GitHub repository [add two Encrypted Secrets](https://docs.github.com/en/actions/reference/encrypted-secrets) using the credentials values above with the environment names of `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY`.
174 | 2. If needed, change the `aws-region` in your `.github/workflows/deploy.yml` file from `us-east-1` to your own region.
175 | 3. Trigger a deploy by navigating to the Deploy workflow and clicking "Run workflow".
176 |
177 |
182 |
--------------------------------------------------------------------------------
/docs/assets.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | id: assets
3 | title: JavaScript & Assets
4 | toc_max_heading_level: 2
5 | ---
6 |
7 | # JavaScript & Assets
8 |
9 | import DocLink from "../src/components/DocLink.js"
10 | import ThemedImage from '@theme/ThemedImage'
11 | import useBaseUrl from "@docusaurus/useBaseUrl"
12 |
13 | Assets require a to link properly when using API Gateway. For Function URLs, the work out of the box. Both API Gateway and Function URLs can benefit from a CloudFront CDN to cache `/assets` and avoid hitting your backend function on each request.
14 |
15 | ## Serving Static Assets
16 |
17 | Our cookiecutter project leverages Rails' built in ability to serve static assets. We do this by setting this environment variable in your `Dockerfile`.
18 |
19 | ```docker title="Dockerfile"
20 | ENV RAILS_SERVE_STATIC_FILES=1
21 | ```
22 |
23 | We also add this configuration to your `config/environments/production.rb` file. In this case we are setting the cache control to 30 days, which you can change. The `X-Lamby-Base64` header signals to the Lamby rack adapter that the content requires base64 binary encoding.
24 |
25 | ```ruby title="config/environments/production.rb"
26 | config.public_file_server.headers = {
27 | 'Cache-Control' => "public, max-age=#{30.days.seconds.to_i}",
28 | 'X-Lamby-Base64' => '1'
29 | }
30 | ```
31 |
32 | ## Adding CloudFront
33 |
34 | [CloudFront](https://aws.amazon.com/cloudfront/) is an amazing CDN and is pretty easy to setup with Rails. Simply point CloudFront to your Rails app and allow the origin to set the cache headers. Because we set the `public_file_server` headers above, everything should work out perfectly. Assuming you have setup a via CloudFront, here is how to setup an behavior for your `/assets` path. From your CloudFront distribution
35 |
36 | - Click the "Behaviors" tab
37 | - Click "Create Behavior" button
38 | - Path Pattern: `/assets/*`
39 | - Select your API Gateway or Function URL origin.
40 | - Compress objects automatically: Yes
41 | - Viewer protocol policy: Redirect HTTP to HTTPS
42 | - Allowed HTTP Methods: GET, HEAD
43 | - Restrict viewer access: No
44 | - 🔘 Cache policy and origin request policy (recommended)
45 | - Cache policy: CachingOptimized
46 | - Origin request policy: None
47 |
48 | ## JavaScript Ready
49 |
50 | Our cookiecutter project is ready to hit the ground running with all the latest Rails defaults for JavaScript & CSS development. We do this by adding Node.js to the development container which is also used to build your production image. See our guide for details.
51 |
52 | For example, we can add the [TailwindCSS Rails](https://github.com/rails/tailwindcss-rails) gem, run the `./bin/rails tailwindcss:install` command, and edit the temporary starter index page like so. Once redeployed, we should see our Hello TailwindCSS page working correctly.
53 |
54 | ```ruby title="Gemfile"
55 | gem 'tailwindcss-rails'
56 | ```
57 |
58 | ```html title="app/views/application/index.html.erb"
59 |
Hello TailwindCSS
65 | ```
66 |
67 |
74 |
75 |
--------------------------------------------------------------------------------
/docs/cold-starts.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | id: cold-starts
3 | toc_max_heading_level: 2
4 | ---
5 |
6 | # Cold Starts
7 |
8 | import DocLink from "../src/components/DocLink.js";
9 | import ThemedImage from "@theme/ThemedImage";
10 | import useBaseUrl from "@docusaurus/useBaseUrl";
11 |
12 | Cold starts (or init times) are an [incredibly addictive](https://docs.aws.amazon.com/lambda/latest/dg/runtimes-context.html#runtimes-lifecycle) topic. In many cases they can be ignored as an optimization to perform when the time and data suggests action. In practice, the more traffic your function handles the less likely cold starts are an issue since they statistically disappear under the [99th percentile](https://aws.amazon.com/blogs/aws/amazon-cloudwatch-update-percentile-statistics-and-new-dashboard-widgets/). However in rare cases, you may want to optimize for them. This guide can help you make decisions on how to go about it. It also descibes how AWS may be doing this for you already with [Proactive Initialization](#proactive-initialization).
13 |
14 | :::info
15 | Modest sized Rails applications generally boot within 3 to 5 seconds. This happens exactly once for the duration of the function's lifecycle which could last for 30 minutes or more and service a huge amount of traffic with no latency.
16 | :::
17 |
18 | ## Monitoring with CloudWatch
19 |
20 | You can not optimize what you do not measure. Thankfully, AWS Lambda logs initialization time of your function to CloudWatch logs which you can query using [CloudWatch Insights](https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/AnalyzingLogData.html).
21 |
22 | This query below will give you a nice percentile breakdown for your application's init duration which is the code outside the handler method. Feel free to change the bin bucket from 1 hour to whatever time helps you. For example, using `1d` (1 day) over a longer duration (weeks) allows you to see statistical trends. In general, your `p50` should be under 5 seconds.
23 |
24 | ```coffee
25 | fields @initDuration
26 | | filter ispresent(@initDuration)
27 | | stats pct(@initDuration, 5) as p5,
28 | pct(@initDuration, 50) as p50,
29 | pct(@initDuration, 95) as p95,
30 | pct(@initDuration, 99) as p99
31 | by bin(1h)
32 | ```
33 |
34 |
45 |
46 | :::info
47 | See the [Proactive Initialization](#proactive-initialization) section for more details on how to use Lamby's new CloudWatch Metrics to measure both cold starts and proactive initialization.
48 | :::
49 |
50 | ## Proactive Initialization
51 |
52 | As described in [AJ Stuyvenberg's](https://twitter.com/astuyve) post on the topic [Understanding AWS Lambda Proactive Initialization](https://aaronstuyvenberg.com/posts/understanding-proactive-initialization), AWS Lambda may have solved some of your cold start issues for you since March 2023. Stated in an excerpt [from AWS' docs](https://aaronstuyvenberg.com/posts/understanding-proactive-initialization):
53 |
54 | > For functions using unreserved (on-demand) concurrency, Lambda occasionally pre-initializes execution environments to reduce the number of cold start invocations. For example, Lambda might initialize a new execution environment to replace an execution environment that is about to be shut down. If a pre-initialized execution environment becomes available while Lambda is initializing a new execution environment to process an invocation, Lambda can use the pre-initialized execution environment.
55 |
56 | This means the [Monitoring with CloudWatch](#monitoring-with-cloudwatch) is just half the picture. But how much is your application potentially benefiting from proactive inits? Since [Lamby v5.1.0](https://github.com/rails-lambda/lamby/pull/169), you can now find out easily using CloudWatch Metrics. To turn metrics on, enable the config like so:
57 |
58 | ```rails title="config/environments/production.rb"
59 | config.lamby.cold_start_metrics = true
60 | ```
61 |
62 | Lamby will now publish [CloudWatch Embedded Metrics](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch_Embedded_Metric_Format.html) in the `Lamby` namespace with a custom dimension for each application's name. Captured metrics include counts for Cold Starts vs. Proactive Initializations. Here is an example running sum of 3 days of data for a large Rails application in the `us-east-1` region.
63 |
64 |
71 |
72 | This data shows the vast majority of your initialized Lambda Containers are proactively initialized. Hence, no cold starts are felt by end users or consumers of your function. If you need to customize the name of your Rails application in the CloudWatch Metrics dimension, you can do so using this config.
73 |
74 | ```rails title="config/environments/production.rb"
75 | config.lamby.metrics_app_name = 'MyServiceName'
76 | ```
77 |
78 | ## Bootsnap by Shopify
79 |
80 | Reducing your Rails applications boot time should be your first optimization option against true cold starts. [Bootsnap](https://github.com/Shopify/bootsnap) has been developed by Shopify to speed up Rails boot time for production environments using a mix of compile and load path caches. When complete, your deployed container will have everything it needs to boot faster!
81 |
82 | How much faster? Generally 1 to 3 seconds depending on your Lambda application. Adding Bootsnap to your Rails Lambda application is straightforward. First, add the gem to your production group in your `Gemfile`.
83 |
84 | ```ruby title="Gemfile"
85 | group :production do
86 | gem 'bootsnap'
87 | end
88 | ```
89 |
90 | Next, we need to add the Bootsnap caches with your deployed container. Add these lines to your project's `Dockerfile` after your `COPY . .` declaration. It will run two commands. The first is the standard Bootsnap precompile which builds both the Ruby ISeq & YAML caches. The second line loads your application into memory and thus automatically creates the `$LOAD_PATH` cache.
91 |
92 | ```dockerfile title="Dockerfile"
93 | ENV BOOTSNAP_CACHE_DIR=/var/task/tmp/cache
94 | RUN bundle exec bootsnap precompile --gemfile . \
95 | && bundle exec ruby config/environment.rb
96 | ```
97 |
98 | Afterward you should be able to verify that Bootsnap's caches are working. Measure your cold starts using a 1 day stats duration for better long term visibility.
99 |
100 | ## Other Cold Start Factors
101 |
102 | Most of these should be considered before using [Provisioned Concurrency](#provisioned-concurrency). Also note, that [Proactive Initialization](#proactive-initialization) may be masking some of these optimizations for you already. That said, consider the following:
103 |
104 | **Client Connect Timeouts** - Your Lambda application may be used by clients who have a low [http open timeout](https://ruby-doc.org/stdlib/libdoc/net/http/rdoc/Net/HTTP.html#open_timeout-attribute-method). If this is the case, you may have to increase client timeouts, leverage provisioned concurrency, and/or reduce initialization time.
105 |
106 | **Update Ruby** - New versions of Ruby typically boot and run faster. Since our project uses custom Ruby Ubuntu with Lambda containers, updating Ruby should be as easy as changing a few lines of code.
107 |
108 | **Memory & vCPU** - It has been proposed that increased Memory/vCPU could reduce cold starts. We have not seen any evidence of this. For example, we recommend that Rails functions use `1792` for its `MemorySize` equal to 1 vCPU. Any lower would sacrifice response times. Tests showed that increasing this to `3008` equal to 2 vCPUs did nothing for a basic Rails application but cost more. However, if your function does concurrent work doing initialization, consider testing different values here.
109 |
110 | **Lazy DB/Resource Connections** - Rails is really good at lazy loading database connections. This is important to keep the "Init" phase of the [Lambda execution lifecycle](https://docs.aws.amazon.com/lambda/latest/dg/runtimes-context.html#runtimes-lifecycle) quick and under 10s. This allows the first "Invoke" to connect to other resources. To keep init duration low, make sure your application does not eagerly connect to resources. Both ActiveRecord and Memcached w/Dalli are lazy loaded by default.
111 |
112 | **ActiveRecord Schema Cache** - Commonly called Rails' best kept performance feature, the [schema cache](https://kirshatrov.com/2016/12/13/schema-cache/) can help reduce first request response time after Rails is initialized. So it should not help the init time but it could very easily help the first invoke times.
113 |
114 | **Reduce Image Size** - Sort of related to your Ruby version, always make sure that your ECR image is as small as possible. Lambda Containers supports up to 10GB for your image. There is no data on how much this could effect cold starts. So please [share your stories](https://github.com/rails-lambda/lamby/discussions).
115 |
116 | ## Provisioned Concurrency
117 |
118 | :::caution
119 | Provisioned concurrency comes with additional execution costs. Now that we have [Proactive Initialization](#proactive-initialization) it may never be needed.
120 | :::
121 |
122 | AWS provides an option called [Provisioned Concurrency](https://docs.aws.amazon.com/lambda/latest/dg/configuration-concurrency.html) (PC) which allows you to warm instances prior to receiving requests. This lets you execute Lambda functions with super low latency and no cold starts. Besides setting a static PC value, there are two fundamental methods for scaling with Provisioned Concurrency. Please use the [Concurrency CloudWatch Metrics](#concurrency-cloudwatch-metrics) section to help you make a determination on what method is right for you.
123 |
124 | ### Requirements
125 |
126 | Our cookiecutter includes both an `AutoPublishAlias` and an all at once `DeploymentPreference`. The publish alias is needed for provisioned concurrency. You can read about both in AWS "[Deploying serverless applications gradually](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/automating-updates-to-serverless-apps.html)" guide. The code snippets below assume your function's logical resource is `RailsLambda` and you have an alias named `live`.
127 |
128 | ### Auto Scaling
129 |
130 | Here we are creating an [`AWS::AutoScaling::ScalingPolicy`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-as-policy.html) and a [`AWS::ApplicationAutoScaling::ScalableTarget`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-applicationautoscaling-scalabletarget.html) which effectively creates a managed CloudWatch Rule that monitors your application to scale it up and down as needed. In this example we set a maximum of `40` and minimal of `5` provisioned instances. We have a `TargetValue` of `0.4` which is a percentage of provisioned concurrency to trigger the CloudWatch Rules via the `ProvisionedConcurrencyUtilization` metric. In this case, lower equals a more aggressive scaling strategy.
131 |
132 | ```yaml title="template.yaml"
133 | Resources:
134 | RailsLambda:
135 | # ...
136 | Properties:
137 | ProvisionedConcurrencyConfig:
138 | ProvisionedConcurrentExecutions: 5
139 |
140 | RailsScalableTarget:
141 | Type: AWS::ApplicationAutoScaling::ScalableTarget
142 | Properties:
143 | MaxCapacity: 40
144 | MinCapacity: 5
145 | ResourceId: !Sub function:${RailsLambda}:live
146 | RoleARN: !Sub arn:aws:iam::${AWS::AccountId}:role/aws-service-role/lambda.application-autoscaling.amazonaws.com/AWSServiceRoleForApplicationAutoScaling_LambdaConcurrency
147 | ScalableDimension: lambda:function:ProvisionedConcurrency
148 | ServiceNamespace: lambda
149 | DependsOn: RailsLambdaAliaslive
150 |
151 | RailsScalingPolicy:
152 | Type: AWS::ApplicationAutoScaling::ScalingPolicy
153 | Properties:
154 | PolicyName: utilization
155 | PolicyType: TargetTrackingScaling
156 | ScalingTargetId: !Ref RailsScalableTarget
157 | TargetTrackingScalingPolicyConfiguration:
158 | TargetValue: 0.4
159 | PredefinedMetricSpecification:
160 | PredefinedMetricType: LambdaProvisionedConcurrencyUtilization
161 | ```
162 |
163 | Please read this related article. [Lambda Provisioned Concurrency AutoScaling is Awesome. Make sure you understand how it works!](https://georgemao.medium.com/understanding-lambda-provisioned-concurrency-autoscaling-735eb14040cf) It goes into great detail on how short traffic bursts (common for most of us) can be missed by the standard CloudWatch Alarms and possible remediation to scale up.
164 |
165 | ### Using a Schedule
166 |
167 | In this example we have measured via CloudWatch Metrics (image above) that our concurrent executions never really goes past `40` instances during daytime peak usage. In this case to totally remove cold starts from a small percentage of requests we can draw a big virtual box around the curves above to always keep `40` instances warm during our peak times starting at 6am EST and going back down to `0` Provisioned Concurrency at 11PM EST. Here is how we would do that with a Provisioned Concurrency schedule.
168 |
169 | ```yaml title="template.yaml"
170 | Resources:
171 | RailsScalableTarget:
172 | Type: AWS::ApplicationAutoScaling::ScalableTarget
173 | Properties:
174 | MaxCapacity: 0
175 | MinCapacity: 0
176 | ResourceId: !Sub function:${RailsLambda}:live
177 | RoleARN: !Sub arn:aws:iam::${AWS::AccountId}:role/aws-service-role/lambdaapplication-autoscaling. amazonaws.com/AWSServiceRoleForApplicationAutoScaling_LambdaConcurrency
178 | ScalableDimension: lambda:function:ProvisionedConcurrency
179 | ServiceNamespace: lambda
180 | ScheduledActions:
181 | - ScalableTargetAction:
182 | MaxCapacity: 0
183 | MinCapacity: 0
184 | ScheduledActionName: ScaleDown
185 | Schedule: "cron(0 3 * * ? *)"
186 | - ScalableTargetAction:
187 | MaxCapacity: 40
188 | MinCapacity: 40
189 | ScheduledActionName: ScaleUp
190 | Schedule: "cron(0 10 * * ? *)"
191 | DependsOn: RailsLambdaAliaslive
192 | ```
193 |
194 | ### Concurrency CloudWatch Metrics
195 |
196 | The graphs below were made using the following managed AWS Lambda CloudWatch Metrics. Please make sure to use your deploy alias of `:live` when targeting your functions resource in these reports.
197 |
198 | - `ConcurrentExecutions`
199 | - `ProvisionedConcurrentExecutions`
200 | - `ProvisionedConcurrencySpilloverInvocations`
201 |
202 | This chart shows that a static `ProvisionedConcurrentExecutions` of `5` can handle most invocations for the first 3 days. Later, for the remaining 4 days, auto scaling was added with a `TargetValue` of `0.4`. Because of the workload's spiky nature, the Invocations look almost 100% provisioned. However, the concurrent executions show otherwise.
203 |
204 |
211 |
212 | Here is a 7 day view from the 4 day mark above. The `TargetValue` is still set to `0.4`. It illustrates how the default CloudWatch Rule for `ProvisionedConcurrencyUtilization` metrics over a 3 minute span are not quick enough to scale PC. It is possible to use a `TargetValue` of `0.1` to force the PC lines to meet the blue. But your cost at this point would be unrealistically high.
213 |
214 |
221 |
222 | ## Gradual Deployments
223 |
224 | As mentioned in the [Provisioned Concurrency](#provisioned-concurrency) section we use a simple `DeploymentPreference` value called `AllAtOnce`. When a deploy happens, Lambda will need to download your new ECR image before your application is initialized. In certain high traffic scenarios along with a potentially slow loading application, deploys can be a thundering herd effect causing your concurrency to spike and a small percentage of users having longer response times.
225 |
226 | Please see AWS' "[Deploying serverless applications gradually](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/automating-updates-to-serverless-apps.html)" guide for full details. However, one way to soften this would be to roll out your new code in 10 minutes total via the `Linear10PercentEvery1Minute` deployment preference. This will automatically create a [AWS CodeDeploy](https://aws.amazon.com/codedeploy/) application and deployments for you. So cool!
227 |
--------------------------------------------------------------------------------
/docs/cpu-architecture.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | id: cpu
3 | title: CPU Architecture
4 | toc_max_heading_level: 2
5 | ---
6 |
7 | import DocLink from "../src/components/DocLink.js";
8 |
9 | # CPU Architecture
10 |
11 | Our [cookiecutter](https://github.com/rails-lambda/lamby-cookiecutter) project defaults to building a Linux container image targeting the `arm64` architecture vs the traditional `x86_64` cpu type. Applications that use arm64 (AWS Graviton2 processor) can achieve significantly better price and performance than the equivalent workloads running an on x86_64 architecture.
12 |
13 | Deploying arm64 applications is still a relatively new process and requires a few special considerations from local development to your CI/CD tooling. AWS Lambda makes this easy using the [Architectures](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-function.html#cfn-lambda-function-architectures) setting of the `AWS::Lambda::Function` CloudFormation resource. However, here are a few things you should know.
14 |
15 | ## Docker Images
16 |
17 | Most base Docker images are now build for [multiple platforms](https://www.docker.com/blog/faster-multi-platform-builds-dockerfile-cross-compilation-guide/). Consider the following `Dockerfile`:
18 |
19 | ```dockerfile
20 | FROM ruby:3.2-bullseye
21 | ```
22 |
23 | How does Docker know which platform to use? The anwser is to use the default platform of the host. If you are on a M1 or M2 Mac, arm64 would be the platform used. Which platforms are in a specific base image? We can find out using the `docker manifest` command. For example:
24 |
25 | ```shell
26 | $ docker manifest inspect ruby:3.2 | grep arch
27 | "architecture": "amd64",
28 | "architecture": "arm64",
29 | $ docker manifest inspect | grep arch
30 | "architecture": "amd64",
31 | "architecture": "arm64",
32 | ```
33 |
34 | All the images in our starter project are multi-platform. This means any host can be used for development. Your computer, Codespaces, etc will use the proper platform image variants.
35 |
36 | ## Deployment Gotchas
37 |
38 | Though there are numerous ways to deploy containers using techniques such as emulation. However, we recommend you following one simple rule. Matching your “Development Host OS/Arch” to that of your target “Deployment Host OS/Arch” provides the least development friction. Use a CI/CD platform that matches your deployment target.
39 |
40 | :::caution
41 | Currently GitHub Actions does not support native arm64 runners. They are [working to add](https://github.com/actions/runner-images/issues/5631) this feature.
42 | :::
43 |
44 | Our guide has your first deploy happening from your local machine. Since we default to `arm64` this should work fine if you are on a Mac with Apple Silicon. But what if you are on a Windows or Linux system with an `x86_64` architecture? Your function will not work since your application's system dependences (like mysq2) will be compiled for the wrong architecture. Depending on your needs, you may have to switch back to `x86_64` as described below.
45 |
46 | For more information on deployments, see our guide.
47 |
48 | ## Switching to x86_64
49 |
50 | Based off the current state of our [cookiecutter](https://github.com/rails-lambda/lamby-cookiecutter) project, here are the changes required to switch to a `x86_64` deployment target. First, change your CircleCI workflows default machine from `arm.large`` to a standard large.
51 |
52 | ```diff title=".circleci/config.yml"
53 | default-machine: &default-machine
54 | machine:
55 | image: ubuntu-2204:current
56 | docker_layer_caching: true
57 | - resource_class: arm.large
58 | + resource_class: large
59 | ```
60 |
61 | Now open up your AWS SAM serverless `template.yaml` file, find the `Globals` section and change your Architecture property from `arm64` to `x86_64`.
62 |
63 | ```diff title="template.yaml"
64 | Globals:
65 | Function:
66 | Architectures:
67 | - - arm64
68 | + - x86_64
69 | ```
70 |
--------------------------------------------------------------------------------
/docs/custom-domain.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | id: custom-domain
3 | title: Custom Domain Names
4 | toc_max_heading_level: 3
5 | ---
6 |
7 | # Custom Domain Names
8 |
9 | import DocLink from "../src/components/DocLink.js";
10 |
11 | ## Function URL
12 |
13 | If you are following our latest pattern, then you are using Lambda's free Function URLs (FURL) which allows to work out of the box. Using a custom domain name with a FURL is as easy as adding CloudFront. To see your FURL in the AWS Console, open the Lambda section -> Click Your Function Name -> Open Versions Tab -> Open Configuration Tab -> Click alias: live. Your Function URL will appear in the upper right. Ex: `uniquestring.lambda-url.us-east-1.on.aws`. Custom Domain Name Steps:
14 |
15 | - [Secure Certificate with ACM](#secure-certificate-with-acm)
16 | - [Simple CloudFront Distribution](#simple-cloudfront-distribution)
17 | - [Create a Route53 Record](#create-a-route53-record)
18 |
19 | ## API Gateway
20 |
21 | For API Gateway Lamby users, their Custom Domain Name featue is the only way to get working correctly by removing the stage path. You can optionally add a CloudFront distribution above this for edge caching. Custom Domain Name Steps:
22 |
23 | - [Secure Certificate with ACM](#secure-certificate-with-acm)
24 | - [API Gateway Custom Domain Names](#api-gateway-custom-domain-names)
25 | - [Simple CloudFront Distribution](#simple-cloudfront-distribution)
26 | - [Create a Route53 Record](#create-a-route53-record)
27 |
28 | ## Individual Steps
29 |
30 | ### Secure Certificate with ACM
31 |
32 | We are going to use [AWS Certificate Manager](https://docs.aws.amazon.com/acm/latest/userguide/acm-overview.html) to secure your HTTPS traffic under your custom domain. Again, this assumes your domain is setup in Route53 since you will need to validate the certificate and AWS makes that super easy with DNS.
33 |
34 | - AWS Console -> Certificate Manager
35 | - Click "Request a certificate" button.
36 | - Select "Request a public certificate", and "Request a certificate" button.
37 | - Domain name. Ex: `*.example.com`
38 | - Click "Next"
39 | - Select "DNS validation", and "Review".
40 | - Click "Confirm and request" button.
41 | - Click the tiny disclosure triangle beside your domain name.
42 | - Click the "Create record in Route 53" button then "Create" again in modal.
43 | - Click "Continue"
44 |
45 | Verification will take about 3 minutes. From the Certificate Manager dashboard, you can wait and/or hit the 🔄 button and the Status will change from "Pending validation" to "Issued".
46 |
47 | ### Simple CloudFront Distribution
48 |
49 | Basic reference steps for creating a CloudFront distribution. If you are editing an existing CloudFront distribution, some of these settings might be in your default behavior vs the distribution.
50 |
51 | - Origin:
52 | - Origin Domain: Function URL or API Gateway Custom Domain Name Endpoint Config
53 | - Protocol: HTTPS only
54 | - Minimum Origin SSL Protocol: TLSv1.2
55 | - Origin Path: /production (⚠️ Ignore for FURLs. API Gateway stage name.)
56 | - Add Custom Header: X-Forwarded-Host myapp.example.com
57 | - Default Cache Behavior:
58 | - Compress Objects Automatically: Yes
59 | - Viewer Protocol Policy: Redirect HTTP to HTTPS
60 | - Allowed HTTP Methods: GET, HEAD, OPTIONS, PUT, POST, PATCH, DELETE
61 | - Cached HTTP Methods: ✔️ OPTIONS
62 | - Cache key and origin requests:
63 | - 🔘 Legacy cache settings:
64 | - Headers: Include the following headers
65 | - Accept
66 | - Query Strings: All
67 | - Cookies: All
68 | - 🔘 Use origin cache headers
69 | - Settings:
70 | - Price Class: Use only North America and Europe
71 | - Alternate domain name (CNAME): myapp.example.com
72 | - Custom SSL Certificate (select \*.example.com from ACM steps)
73 |
74 | This process takes a while to fully deploy. Once done you will have a CloudFront domain name looking something like `dxxxxxxxxxxxxx.cloudfront.net`. You can now Create a Route53 Record alias for `myapp.example.com` to this CloudFront distribution domain name.
75 |
76 | Feel free to create an additional behavior for the `/assets` path using the `CachingOptimized` cache policy and `None` for the Origin request policy. This will ensure the asset pipeline files are edge-cached and compressed.
77 |
78 | ### Create a Route53 Record
79 |
80 | From here all we need is a DNS entry in Route53 that points to our origin. Typically this would be to your CloudFront distribution. Like the one you may have created for your [Function URLs](#function-url) or your [API Gateway](#api-gateway] custom domain name.
81 |
82 | - AWS Console -> Route 53 -> Hosted zones
83 | - Click on your domain
84 | - Click "Create record"
85 | - Click "Switch to wizard" if not selected already.
86 | - Select "Simple routing"
87 | - Click "Next"
88 | - Click "Define simple record"
89 | - Record name. Ex: `myapp`
90 | - Record type: `A - Routes traffic to an IPv4 address and some AWS resources`
91 | - Value/Route traffic to: (either or)
92 | - Alias to CloudFront distribution
93 | - Endpoint: `dxxxxxxxxxxxxx.cloudfront.net`
94 | - Alias to API Gateway API
95 | - Choose Region: Ex: `us-east-1`
96 | - Choose endpoint: Should autofill, Ex: `d-xxxxxxxxxx.execute-api.us-east-1.amazonaws.com`
97 | - Evaluate target health: `No`
98 | - Click "Define simple record"
99 | - Click "Create records"
100 |
101 | ### API Gateway Custom Domain Names
102 |
103 | Any with API Gateway will need to leverage its Custom Domain Name feature. The only exception would be if you are using an Application Load Balancer without REST API. When completed, your final endpoint would look like this `d-byp3km86t3.execute-api.us-east-1.amazonaws.com` and would then become an CloudFront origin.
104 |
105 | - AWS Console -> API Gateway
106 | - Click "Custom domain names" in the left panel.
107 | - Click "Create" button
108 | - Enter domain name. Ex: `myapp.example.com`
109 | - Use default `TLS 1.2 (recommended)`.
110 | - Endpoint type `Regional`.
111 | - ACM certificate. Select wildcard matching domain from above.
112 | - Click "Create domain name"
113 |
114 | After this has been created, the mappings tab should be selected. From here we need to create an API Mapping to point to your specific API Gateway and stage/path. Assuming it is selected:
115 |
116 | - Click the "API mappings" tab.
117 | - You should see "No API mappings have been configured..." message
118 | - Click "Configure API mappings" button.
119 | - Click "Add new mapping" button.
120 | - Select your API: Ex: `myapp (HTTP - 511n0spvi9)`.
121 | - Select your Stage: Ex: `production`.
122 | - If you see `Stage` and `production` ignore Stage. Known REST bug.
123 | - Leave `Path` empty.
124 | - Click the "Save" button.
125 |
--------------------------------------------------------------------------------
/docs/database.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | id: database
3 | title: Database & VPCs
4 | toc_max_heading_level: 2
5 | ---
6 |
7 | # Database & VPCs
8 |
9 | import DocLink from "../src/components/DocLink.js";
10 |
11 | Any database supported by Ruby or Rails can be used with Lambda assuming your VPC/Network allows those connections. This guide will not get into the details on how to setup or use various databases options within AWS itself like RDS, Aurora, or DynamoDB. However, we will address a few high level topics along with some conventions in our project.
12 |
13 | ## Our Cookiecutter
14 |
15 | Our project does not create a database but it does have a MySQL service attached to the dev container to faciliate quickly iterating toward using one. The two key files' snippets are below. If you decide to use switch to a different database like PostgreSQL, make adjustments to these files and your `Gemfile` as needed.
16 |
17 | ```yaml title="config/database.yml"
18 | default: &default
19 | adapter: mysql2
20 | username: root
21 | password: <%= ENV["MYSQL_ROOT_PASSWORD"] %>
22 | host: <%= ENV.fetch("MYSQL_HOST") { "localhost" } %>
23 | ```
24 |
25 | ```yaml title=".devcontainer/docker-compose.yml"
26 | services:
27 | app:
28 | environment:
29 | - MYSQL_HOST=mysql
30 | - MYSQL_ROOT_PASSWORD=root
31 | ```
32 |
33 | ## VPC Configuration
34 |
35 | Most Rails applications within AWS are deployed to a private subnet(s) within a VPC which allows you to have direct network access to your relational database. For most folks, this is [the default VPC](https://docs.aws.amazon.com/vpc/latest/userguide/default-vpc.html) which means finding your subnet ids and security groups are fairly easy. Once you have those, add this [VpcConfig](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lambda-function-vpcconfig.html) to your project's `template.yaml` file within the existing globals section.
36 |
37 | ```yaml title="template.yaml"
38 | Globals:
39 | Function:
40 | VpcConfig:
41 | SubnetIds:
42 | - subnet-09792e6cd06dd59ad
43 | - subnet-0501f3136415021da
44 | SecurityGroupIds:
45 | - sg-07be99aff5fb14557
46 | ```
47 |
48 | Adding it here will ensure every function within your stack has a common VPC setting. Using a `VpcConfig` should automatically add the `AWSLambdaVPCAccessExecutionRole` managed policy to your Lambda's execution role. If not, you can manually add it to your [`Policies`](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-resource-function.html#sam-function-policies) section.
49 |
50 | ```yaml title="template.yaml"
51 | RailsLambda:
52 | Properties:
53 | Policies:
54 | # highlight-next-line
55 | - AWSLambdaVPCAccessExecutionRole
56 | ```
57 |
58 | ## Database Migrations
59 |
60 | Please see the guide on how to use Lamby's task runner for migrations or other on-demand tasks like Rake.
61 |
62 | ## Using DynamoDB
63 |
64 | In some cases Rails with DynamoDB is an excellent choice. If this sounds right for you, I highly recommend using the [Aws::Record](https://github.com/aws/aws-sdk-ruby-record) gem which leverages the `aws-sdk-dynamodb` in a very Rails like ActiveModel way. Please [share your stories](https://github.com/rails-lambda/lamby/issues/new) with us.
65 |
--------------------------------------------------------------------------------
/docs/environment.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | id: environment
3 | title: ENV Variables & Secrets
4 | toc_max_heading_level: 2
5 | ---
6 |
7 | import DocLink from "../src/components/DocLink.js";
8 |
9 | # Environment Configuration & Secrets
10 |
11 | Most Rails applications require over a dozen environment variables to configure itself along with other popular gems used. Most notable is ActiveRecord's `DATABASE_URL`. There are numerous ways to configure environment variables ranging from "quick and dirty" by adding secrets to your git repo (⚠️) all the way to a strict "separation of config" from code using countless methods to achieve a proper [Twelve-Factor](https://12factor.net/config) application. We want to cover a few topics that may help you pick and choose what works best for you.
12 |
13 | ## Configuration
14 |
15 | You can add simple configurations to your all of your function's environment using SAM's [global section](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-specification-template-anatomy-globals.html). Configurations like these are ones that you feel safe comitting to your git repo.
16 |
17 | ```yaml title="template.yaml"
18 | Globals:
19 | Environment:
20 | Variables:
21 | SOME_SERVICE_URL: https://prod.some-service.com/api
22 | ```
23 |
24 | If you deploy to multiple environments, you can even have these be dynamic by leveraging CloudFormation's [mappings](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/mappings-section-structure.html). Here is an example that builds on our `RailsEnv` parameter.
25 |
26 | ```yaml title="template.yaml"
27 | Mappings:
28 | SomeService:
29 | staging:
30 | Url: https://staging.some-service.com/api
31 | production:
32 | Url: https://prod.some-service.com/api
33 | # ...
34 | Globals:
35 | Environment:
36 | Variables:
37 | SOME_SERVICE_URL: !FindInMap [SomeService, !Ref RailsEnv, Url]
38 | ```
39 |
40 | ## Secrets with Crypteia
41 |
42 | The [Crypteia](https://github.com/rails-lambda/crypteia) package is Rust Lambda Extension for any Runtime/Container to preload SSM Parameters as secure environment variables. It takes advantages of `LD_PRELOAD` to seamlessly fetch values from SSM when a process starts and then injects them as natively accesible Ruby `ENV` variables. Our guide's cookiecutter includes Crypteia already for you via a Docker `COPY` command into the Lambda Extension `/opt` directory.
43 |
44 | ```docker title="Dockerfile"
45 | FROM ruby:3.2-bullseye
46 | # highlight-next-line
47 | COPY --from=ghcr.io/rails-lambda/crypteia-extension-debian:1 /opt /opt
48 | ```
49 |
50 | Usage is simply done by adding variables to your SAM template and accessing the values fetched from SSM like any other environment variable. Please read the Crypteia's [documentation](https://github.com/rails-lambda/crypteia) for full details on how to add [IAM Permissions](https://github.com/rails-lambda/crypteia#iam-permissions) to read SSM Parameters.
51 |
52 | ```title="template.yaml"
53 | Globals:
54 | Environment:
55 | Variables:
56 | SECRET: x-crypteia-ssm:/myapp/SECRET
57 | ```
58 |
59 | ```ruby
60 | ENV['SECRET'] # 1A2B3C4D5E6F
61 | ```
62 |
63 | ## About SECRET_KEY_BASE
64 |
65 | Our project disabled Rails encrypted credentials in favor of a more simple `SECRET_KEY_BASE` setting. The starter project places a temporary value for this environment variable in the `config/initializers/secret_key_base.rb` file. Please remove the `ENV['SECRET_KEY_BASE'] = '0123...'` line and use Crypteia as described above.
66 |
67 | ## Modern IAM Role Usage
68 |
69 | If your application uses other AWS resources like EventBridge or S3, you may be using environment variables like `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY`. **Avoid this pattern.** Instead, please add explicit IAM policies within your `template.yaml` file. They will be attached to your Lambda's [Execution Role](https://docs.aws.amazon.com/lambda/latest/dg/lambda-intro-execution-role.html) and inherently give your Lambda the [needed permissions](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-permissions.html). AWS is constantly making IAM permissions more approachable. There are two high level interfaces within SAM to connect your application to cloud resources. Newest first:
70 |
71 | - [AWS SAM Connectors](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/managing-permissions-connectors.html): Are an AWS SAM abstract resource type, identified as `AWS::Serverless::Connector`, that can be defined in your AWS SAM templates to grant Read and Write access of data and events from a supported AWS resource to another.
72 | - [AWS SAM Policy Templates](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-policy-templates.html): Are pre-defined sets of permissions that you can add to your AWS SAM templates to manage access and permissions between your AWS Lambda functions, AWS Step Functions state machines and the resources they interact with.
73 |
74 | If needed, you can use the lower level [`Policies`](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-resource-function.html#sam-function-policies) property of your `AWS::Serverless::Function` resource to attach any inline policies to your application's IAM Role.
75 |
--------------------------------------------------------------------------------
/docs/observability.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | id: observability
3 | title: Logging & Observability
4 | toc_max_heading_level: 2
5 | ---
6 |
7 | import DocLink from "../src/components/DocLink.js";
8 |
9 | # Logging & Observability
10 |
11 | One of the greatest things of AWS Lambda is that you get all the benfits of CloudWatch logging built into the platform. Logging is just a simple Ruby `puts` command away. Here are a few amazing things to help you succeed with good logging and observability patterns in AWS with CloudWatch.
12 |
13 | ## STDOUT is a Must!
14 |
15 | Lambda is a read-only file system. The Lamby gem will set the `RAILS_LOG_TO_STDOUT` environment variable on your behalf. It also freedom patches the core Ruby `Logger` class to force STDOUT. That said, be on the lookout for any rogue disk-based logging you may have to address. Older Rails applications may have to use a pattern like this.
16 |
17 | ```ruby title="config/environments/production.rb"
18 | logger = ActiveSupport::Logger.new(STDOUT)
19 | logger.formatter = ActiveSupport::Logger::SimpleFormatter.new
20 | config.logger = logger
21 | config.log_level = :info
22 | ```
23 |
24 | ## Using Lograge
25 |
26 | Our installs and configures the [Lograge](https://github.com/roidrage/lograge) gem to reduce CloudWatch data costs while easily allowing CloudWatch Insights to parse and query your logs. If your project is not using Lograge, please consider adding it as we do.
27 |
28 | ```ruby title="Gemfile"
29 | gem 'lograge'
30 | ```
31 |
32 | ```ruby title="config/environments/production.rb"
33 | config.lograge.enabled = true
34 | config.lograge.formatter = Lograge::Formatters::Json.new
35 | config.lograge.custom_payload do |controller|
36 | { requestid: controller.request.request_id }
37 | end
38 | ```
39 |
40 | ## CloudWatch Log Insights
41 |
42 | CloudWatch Logs Insights enables you to interactively search and analyze your log data in Amazon CloudWatch Logs. You can perform queries to help you quickly and effectively respond to operational issues. If an issue occurs, you can use CloudWatch Logs Insights to identify potential causes and validate deployed fixes.
43 |
44 | [🎥 YouTube: Analyze Log Data with CloudWatch Logs Insights](https://www.youtube.com/watch?v=2s2xcwm8QrM)
45 |
46 | ## CloudWatch Embedded Metrics
47 |
48 | The [CloudWatch Embedded Metric Format](https://aws.amazon.com/blogs/mt/enhancing-workload-observability-using-amazon-cloudwatch-embedded-metric-format/) enables CloudWatch to ingest complex high-cardinality application data in the form of logs and easily generate actionable metrics and alarms from them. By sending your logs in the new Embedded Metric Format, you can now easily create custom metrics without having to instrument or maintain separate code, while gaining powerful analytical capabilities on your log data. You can get started with embedded metrics by using our [rails-lambda/aws-embedded-metrics](https://github.com/rails-lambda/aws-embedded-metrics) Ruby gem. The following Lamby-friendly libraries use this format:
49 |
50 | - [Crypteia](https://github.com/rails-lambda/crypteia): SSM Parameters as secure ENV variables.
51 | - [Lambdakiq](https://github.com/rails-lambda/lambdakiq): ActiveJob on SQS & Lambda.
52 |
53 | ## New Relic
54 |
55 | Some older Application Performance Monitor (APM) gems can be used with Lambda but you must flush their data after each request in a way that does not impact response performance. You can do this with the [LambdaPunch](https://github.com/rails-lambda/lambda_punch).
56 |
57 | ```ruby
58 | config.lambda.handled_proc = Proc.new do |_event, context|
59 | LambdaPunch.push { NewRelic::Agent.agent.flush_pipe_data }
60 | LambdaPunch.handled!(context)
61 | end
62 | ```
63 |
64 |
65 |
70 |
71 |
--------------------------------------------------------------------------------
/docs/quick-start.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | id: quick-start
3 | toc_max_heading_level: 2
4 | ---
5 |
6 | import DocLink from "../src/components/DocLink.js";
7 | import ThemedImage from "@theme/ThemedImage";
8 | import useBaseUrl from "@docusaurus/useBaseUrl";
9 |
10 | # Quick Start
11 |
12 | ### Deploy a new Rails APP to Lambda in 5 minutes!
13 |
14 | Lamby can be used with Rails v5 application or higher. The quickest way to learn how Rails works on Lambda is to deploy a new application to your AWS account using our [cookiecutter project](https://github.com/rails-lambda/lamby-cookiecutter) template.
15 |
16 | :::note
17 | Before you get started, make sure that you have Docker installed, an AWS account, and Visual Studio Code open. 🚢 [Install Docker](https://www.docker.com) ⛅️ [AWS Account](https://aws.amazon.com/free) 📝 [Install VS Code](https://code.visualstudio.com)
18 | :::
19 |
20 | ## Rails Project Template
21 |
22 | We created a [rails-lambda/lamby-cookiecutter](https://github.com/rails-lambda/lamby-cookiecutter) repository which allows you to initialize a new project from a GitHub template, commonly called a [cookiecutter](https://github.com/cookiecutter/cookiecutter). Run this terminal command to create a new Rails project with Lamby already installed.
23 |
24 | ```shell
25 | docker run \
26 | --rm \
27 | --interactive \
28 | --volume "${PWD}:/var/task" \
29 | ghcr.io/rails-lambda/lamby-cookiecutter \
30 | "gh:rails-lambda/lamby-cookiecutter"
31 | ```
32 |
33 | You will be prompted for a project name. Choose something short, no spaces, and with underscores for word breaks. Example: `new_service`.
34 |
35 | ```
36 | project_name [my_awesome_lambda]:
37 | ```
38 |
39 | ## Development Container
40 |
41 | :::caution
42 | Is your local computer an `x86_64` system such as an older Intel Mac or Windows? Our starter defaults to an `arm64` deployment target. If needed, see our guide on how to switch to `x86_64`.
43 | :::
44 |
45 | Your new Rails project with Lamby leverages [GitHub Codespaces](https://github.com/features/codespaces) which itself is built atop of the [Development Container](https://containers.dev) specification. In short, this means your project's containers are easy to use by any editor, even outside of Codespaces.
46 |
47 | VS Code makes this incredibly easy. Within a new window, open the command pallet and type "dev container open" and select that action to `Open Folder in Container...`. When prompted, select the project folder created in the previous step.
48 |
49 |
56 |
57 | When the dev container's build is complete, VS Code will display the project folder within the container. This container uses the same base Docker image as the one we are going to deploy to AWS. Unlike the production image, this continer comes with all sorts of build utilties, including the AWS & SAM CLI which we are going to use in the next step to deploy your Rails application to AWS Lambda.
58 |
59 | ## Deploy to Lambda
60 |
61 | Open the integrated terminal by typing `View: Toggle Terminal` in the command pallet. This VS Code terminal is within your development container, an official Ruby Ubuntu image.
62 |
63 |
70 |
71 | First, configure the AWS CLI with your AWS access key and secret.
72 |
73 | ```shell
74 | aws configure
75 | ```
76 |
77 | Now we can run the deploy script which uses the AWS SAM CLI.
78 |
79 | ```shell
80 | ./bin/deploy
81 | ```
82 |
83 | :::caution
84 | Deploy scripts are best run via automated CI/CD system such as GitHub Actions. Please see our full deployment section
85 | :::
86 |
87 | ## Yay! Your're on Rails!
88 |
89 | At the end of the deploy process above, you will see SAM print the outputs for the CloudFormation template being deployed. This includes your Lambda Function URL, a free web server proxy to your Lambda container running Rails.
90 |
91 | ```
92 | CloudFormation outputs from deployed stack
93 | -------------------------------------------------------------------------------------------
94 | Outputs
95 | -------------------------------------------------------------------------------------------
96 | Key RailsLambdaUrl
97 | Description Lambda Function URL
98 | Value https://b4hsncwngvxg6rv67b64r545ly0jrwnk.lambda-url.us-east-1.on.aws/
99 | -------------------------------------------------------------------------------------------
100 |
101 | Successfully created/updated stack - new-service-production in us-east-1
102 | ```
103 |
104 | Open your browser and go to the URL. You should see the familiar welcome to Rails screen.
105 |
106 |
113 |
114 | ## What Just Happened?
115 |
116 | You just deployed a new Rails application to AWS Lambda containers using a basic Ruby Ubuntu Docker base image. Every part of your application is wrapped up neatly in a single CloudFormation stack. This stack has everything you need for a server-side API and/or a client JavaScript application hosted on AWS Lambda. Please take some time to explore how Lamby works in the next sections.
117 |
--------------------------------------------------------------------------------
/docs/running-tasks.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | id: running-tasks
3 | title: Running Tasks & Console
4 | toc_max_heading_level: 3
5 | ---
6 |
7 | import ThemedImage from "@theme/ThemedImage";
8 | import useBaseUrl from "@docusaurus/useBaseUrl";
9 |
10 | It can be common for Rails engineers to fire up the [Rails console](https://guides.rubyonrails.org/command_line.html#bin-rails-console) for some quick debugging or to run code like a Rake task. That said, console'ing into a Lambda function (typically done via SSH) is not possible and requires an event-driven & stateless solution. For this, we have the [Lambda Console](https://github.com/rails-lambda/lambda-console) tool.
11 |
12 |
13 |
20 |
21 |
22 | 💁♂️ https://github.com/rails-lambda/lambda-console
23 |
24 | Lamby leverages the Lambda Console using our Ruby implementation of the spec via the [lambda-console-ruby](https://github.com/rails-lambda/lambda-console-ruby) gem. Here is a quick overview on how to use it for common Rails tasks. Please see the [Lambda Console](https://github.com/rails-lambda/lambda-console) project for complete documentation on the CLI installation and usage.
25 |
26 | :::caution
27 | To use the Lambda Console, please make sure you are using Lamby v5.0.0 or higher.
28 | :::
29 |
30 | ## Common Considerations
31 |
32 | Here are some common considerations when using the [Lambda Console](https://github.com/rails-lambda/lambda-console) to run tasks or interactive commands.
33 |
34 | ### Function Timeout
35 |
36 | Each `run` or `interact` event sent will need to respond within your function's timeout. Since HTTP interactions via most AWS services are limited to 30s, so too is your function's default timeout set to that. If your task takes longer than this, consider temporarily increasing the value in your Cloud Formation template or duplicating your function (copy paste) to a new Lambda Function resource dedicated for running console tasks. A Lambda function can have a maximum of 15m execution time. Just remember that API Gateway integration will always be limited to 30s under the function's timeout. So these timeouts can operate independently.
37 |
38 | ### IAM Security & Permissions
39 |
40 | The [Lambda Console](https://github.com/rails-lambda/lambda-console) leverages AWS SDKs to send invoke events to your function(s). This means you are in full control of the security of your function and whom can invoke it with the following IAM actions for your user or role:
41 |
42 | - `lambda:ListFunctions`
43 | - `lambda:InvokeFunction`
44 |
45 | ### Customizing Runner Patterns
46 |
47 | By default, Lamby v5 and higher allows any command to be run. If you want to enforce which commands can be run at the application layer, please use the Lamby config in your `production.rb` environment file.
48 |
49 | ```ruby
50 | config.lamby.runner_patterns.clear
51 | config.lamby.runner_patterns.push %r{\A/bin/foo.*}
52 | ```
53 |
54 | Here are are clearning/removing the deafault expression pattern of `/.*/` in favor of one that allows any `/bin/foo` command to be run.
55 |
56 |
--------------------------------------------------------------------------------
/docs/webservers.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | id: webservers
3 | title: Web Proxy Integrations
4 | toc_max_heading_level: 2
5 | ---
6 |
7 | # Web Proxy Integrations
8 |
9 | import DocLink from "../src/components/DocLink.js"
10 |
11 | We recommend using Lambda Function URLs which are free, work with JavaScript & CSS assets out of the box, and are easy to map to a custom domain name. However, here are some SAM YAML snippets if you would like to use an alternate web server integration for your application. Remember, Lamby automatically detects which integration you are using.
12 |
13 | :::note
14 | The code snippets below are shown in diff format when compared to the latest files in the cookiecutter project template.
15 | :::
16 |
17 | ## API Gateway HTTP API
18 |
19 | The [HTTP API](https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api.html) is the most modern integration after Function URLs. It is also really easy to add into our template file.
20 |
21 | ```diff
22 | --- template.yaml
23 | +++ template.yaml
24 | @@ -28,14 +28,22 @@ Resources:
25 | DockerTag: web
26 | Properties:
27 | AutoPublishAlias: live
28 | - FunctionUrlConfig:
29 | - AuthType: NONE
30 | DeploymentPreference:
31 | Type: AllAtOnce
32 | + Events:
33 | + HttpApiProxy:
34 | + Type: HttpApi
35 | + Properties:
36 | + ApiId: !Ref RailsHttpApi
37 | MemorySize: 1792
38 | PackageType: Image
39 | Timeout: 30
40 |
41 | + RailsHttpApi:
42 | + Type: AWS::Serverless::HttpApi
43 | + Properties:
44 | + StageName: !Ref RailsEnv
45 | ```
46 |
47 |
48 | ## API Gateway REST API
49 |
50 | The [REST API](https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-rest-api.html) is a little more verbose, but it essentially sets up a simple proxy that Lamby can use. The integration `uri` lines use the `:live` alias since our starter defaults to using an `AutoPublishAlias: live`
51 |
52 | ## Application Load Balancer
53 |
54 | Using Lambda's [ALB Integration](https://docs.aws.amazon.com/lambda/latest/dg/services-alb.html) is a great way to setup your application on a private VPC. However, they limit response payloads to less than 1MB vs. the 6MB limit for API Gateway. Using [Rack::Deflater](https://gist.github.com/metaskills/363e39e2e8cbccf280b5d5804b384bd2) can help with this if needed. These resources make use of the VPC subnets and security groups mentioned in the guide.
55 |
56 | ```diff
57 | --- template.yaml
58 | +++ template.yaml
59 | @@ -28,14 +28,52 @@ Resources:
60 | DockerTag: web
61 | Properties:
62 | AutoPublishAlias: live
63 | - FunctionUrlConfig:
64 | - AuthType: NONE
65 | DeploymentPreference:
66 | Type: AllAtOnce
67 | MemorySize: 1792
68 | PackageType: Image
69 | Timeout: 30
70 |
71 | + RailsLoadBalancer:
72 | + Type: AWS::ElasticLoadBalancingV2::LoadBalancer
73 | + Properties:
74 | + Scheme: internal
75 | + SubnetIds:
76 | + - subnet-09792e6cd06dd59ad
77 | + - subnet-0501f3136415021da
78 | + SecurityGroupIds:
79 | + - sg-07be99aff5fb14557
80 | +
81 | + RailsLoadBalancerHttpsListener:
82 | + Type: AWS::ElasticLoadBalancingV2::Listener
83 | + Properties:
84 | + Certificates:
85 | + - CertificateArn: arn:aws:acm:us-east-1:123456789012:certificate/38613b58-c21e-11eb-8529-0242ac130003
86 | + DefaultActions:
87 | + - TargetGroupArn: !Ref RailsLoadBalancerTargetGroup
88 | + Type: forward
89 | + LoadBalancerArn: !Ref RailsLoadBalancer
90 | + Port: 443
91 | + Protocol: HTTPS
92 | +
93 | + RailsLoadBalancerTargetGroup:
94 | + Type: AWS::ElasticLoadBalancingV2::TargetGroup
95 | + DependsOn: RailsLambdaInvokePermission
96 | + Properties:
97 | + TargetType: lambda
98 | + TargetGroupAttributes:
99 | + - Key: lambda.multi_value_headers.enabled
100 | + Value: true
101 | + Targets:
102 | + - Id: !GetAtt RailsLambda.Arn
103 | +
104 | + RailsLambdaInvokePermission:
105 | + Type: AWS::Lambda::Permission
106 | + Properties:
107 | + FunctionName: !GetAtt RailsLambda.Arn
108 | + Action: "lambda:InvokeFunction"
109 | + Principal: elasticloadbalancing.amazonaws.com
110 | ```
111 |
--------------------------------------------------------------------------------
/docusaurus.config.js:
--------------------------------------------------------------------------------
1 | // @ts-check
2 | const path = require("path");
3 | const lightCodeTheme = require("prism-react-renderer/themes/github");
4 | const darkCodeTheme = require("prism-react-renderer/themes/dracula");
5 |
6 | /** @type {import('@docusaurus/types').Config} */
7 | const config = {
8 | title: "Lamby - Simple Rails & AWS Lambda Integration using Rack",
9 | url: "https://lamby.cloud",
10 | baseUrl: "/",
11 | onBrokenLinks: "throw",
12 | onBrokenMarkdownLinks: "warn",
13 | favicon: "img/favicon.ico",
14 | projectName: "lamby-site",
15 | trailingSlash: false,
16 | organizationName: "rails-lambda",
17 | deploymentBranch: "gh-pages",
18 | i18n: {
19 | defaultLocale: "en",
20 | locales: ["en"],
21 | },
22 | presets: [
23 | [
24 | "classic",
25 | /** @type {import('@docusaurus/preset-classic').Options} */
26 | ({
27 | docs: {
28 | sidebarPath: require.resolve("./sidebars.js"),
29 | editUrl: "https://github.com/rails-lambda/lamby-site/tree/master",
30 | },
31 | blog: {
32 | showReadingTime: true,
33 | },
34 | theme: {
35 | customCss: require.resolve("./src/css/custom.css"),
36 | },
37 | }),
38 | ],
39 | ],
40 | markdown: {
41 | mermaid: true,
42 | },
43 | themes: ["@docusaurus/theme-mermaid"],
44 | themeConfig:
45 | /** @type {import('@docusaurus/preset-classic').ThemeConfig} */
46 | ({
47 | navbar: {
48 | title: "Lamby",
49 | logo: {
50 | alt: "Lamby Logo",
51 | src: "img/lamby-logo-small.png",
52 | },
53 | items: [
54 | {
55 | href: "/docs/quick-start",
56 | label: "Quick Start",
57 | position: "left",
58 | },
59 | {
60 | type: "doc",
61 | docId: "anatomy",
62 | position: "left",
63 | label: "Documentation",
64 | },
65 | {
66 | to: "/blog",
67 | label: "Updates Blog",
68 | position: "left",
69 | },
70 | {
71 | href: "https://github.com/rails-lambda/lamby",
72 | label: "GitHub",
73 | position: "right",
74 | },
75 | ],
76 | },
77 | footer: {
78 | style: "light",
79 | links: [
80 | {
81 | title: "Guides",
82 | items: [
83 | {
84 | label: "Quick Start",
85 | to: "/docs/quick-start",
86 | },
87 | {
88 | label: "Documentation",
89 | to: "/docs/anatomy",
90 | },
91 | ],
92 | },
93 | {
94 | title: "Community",
95 | items: [
96 | {
97 | label: "Twitter @CustomInkTech",
98 | href: "https://twitter.com/custominktech",
99 | },
100 | {
101 | label: "Technology Blog on Dev.to",
102 | href: "https://dev.to/customink",
103 | },
104 | ],
105 | },
106 | {
107 | title: "More",
108 | items: [
109 | {
110 | label: "Lamby Blog",
111 | to: "/blog",
112 | },
113 | {
114 | label: "GitHub Project",
115 | href: "https://github.com/rails-lambda/lamby",
116 | },
117 | ],
118 | },
119 | ],
120 | copyright: `${new Date().getFullYear()} - Made with ❤️ by Custom Ink | Tech`,
121 | },
122 | prism: {
123 | theme: lightCodeTheme,
124 | darkTheme: darkCodeTheme,
125 | additionalLanguages: ["ruby", "docker", "yaml"],
126 | },
127 | metadata: [
128 | {
129 | name: "keywords",
130 | content: "rails, rack, lambda, serverless, containers",
131 | },
132 | ],
133 | colorMode: {
134 | defaultMode: "light",
135 | disableSwitch: false,
136 | respectPrefersColorScheme: true,
137 | },
138 | }),
139 | };
140 |
141 | module.exports = config;
142 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "lamby",
3 | "version": "0.0.0",
4 | "private": true,
5 | "scripts": {
6 | "docusaurus": "docusaurus",
7 | "start": "docusaurus start --host 0.0.0.0 --port 3080 --no-open",
8 | "build": "docusaurus build",
9 | "swizzle": "docusaurus swizzle",
10 | "deploy": "docusaurus deploy",
11 | "clear": "docusaurus clear",
12 | "serve": "docusaurus serve",
13 | "write-translations": "docusaurus write-translations",
14 | "write-heading-ids": "docusaurus write-heading-ids"
15 | },
16 | "dependencies": {
17 | "@docusaurus/core": "2.2.0",
18 | "@docusaurus/preset-classic": "2.2.0",
19 | "@docusaurus/theme-mermaid": "^2.2.0",
20 | "@mdx-js/react": "^1.6.22",
21 | "clsx": "^1.2.1",
22 | "prism-react-renderer": "^1.3.5",
23 | "react": "^17.0.2",
24 | "react-dom": "^17.0.2"
25 | },
26 | "devDependencies": {
27 | "@docusaurus/module-type-aliases": "2.2.0"
28 | },
29 | "browserslist": {
30 | "production": [
31 | ">0.5%",
32 | "not dead",
33 | "not op_mini all"
34 | ],
35 | "development": [
36 | "last 1 chrome version",
37 | "last 1 firefox version",
38 | "last 1 safari version"
39 | ]
40 | },
41 | "engines": {
42 | "node": ">=16.14"
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/sidebars.js:
--------------------------------------------------------------------------------
1 | // @ts-check
2 | /** @type {import('@docusaurus/plugin-content-docs').SidebarsConfig} */
3 | const sidebars = {
4 | docsSidebar: [
5 | { type: 'doc', id: 'quick-start' },
6 | { type: 'doc', id: 'anatomy' },
7 | { type: 'doc', id: 'cpu' },
8 | { type: 'doc', id: 'environment' },
9 | { type: 'doc', id: 'database' },
10 | { type: 'doc', id: 'assets' },
11 | { type: 'doc', id: 'observability' },
12 | { type: 'doc', id: 'activejob' },
13 | { type: 'doc', id: 'running-tasks' },
14 | { type: 'doc', id: 'custom-domain' },
15 | { type: 'doc', id: 'webservers' },
16 | { type: 'doc', id: 'cold-starts' }
17 | ]
18 | };
19 | module.exports = sidebars;
20 |
--------------------------------------------------------------------------------
/src/components/DocLink.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 |
3 | const DocNames = {
4 | anatomy: "How Lamby Works",
5 | cpu: "CPU Architecture",
6 | environment: "ENV Variables & Secrets",
7 | assets: "JavaScript & Assets",
8 | deploy: "Build & Deploy",
9 | "custom-domain": "Custom Domain Names",
10 | activejob: "ActiveJob & Background Processing",
11 | observability: "Logging & Observability",
12 | database: "Database & VPCs",
13 | webservers: "Web Proxy Integrations",
14 | };
15 |
16 | const titleize = function (str) {
17 | return str
18 | .replace(/(_|-)/g, " ")
19 | .split(" ")
20 | .map((w) => w.charAt(0).toUpperCase() + w.toLowerCase().slice(1))
21 | .join(" ");
22 | };
23 |
24 | export default function DocLink({ id, name, anchor }) {
25 | const aLink = name || DocNames[id] || titleize(id);
26 | if (anchor) {
27 | return {aLink};
28 | } else {
29 | return {aLink};
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/components/HomepageFeatures/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import clsx from 'clsx';
3 | import styles from './styles.module.css';
4 |
5 | const FeatureList = [
6 | {
7 | title: 'Event-Based with Rack',
8 | description: (
9 | <>
10 | No webserver needed! Lamby is as a Rack adapter that converts any AWS Lambda integration into Rack objects that are sent directly to your app. Lamby supports Function URLs, API Gateway (HTTP or REST), and Application Load Balancer (ALB) integrations. Background jobs and other events are supported.
11 | >
12 | ),
13 | },
14 | {
15 | title: 'Container-First Principles',
16 | description: (
17 | <>
18 | Any containerized Rails application can run on AWS Lambda. Compute can rapidly scale to meet any demand and back down to zero for cost savings. Images have access to 10 GB size limits, 10 GB of memory, & as many as 6 vCPUs. Lamby even promotes the use of the same containers for development.
19 | >
20 | ),
21 | },
22 | {
23 | title: 'Easy IaC to CI/CD',
24 | description: (
25 | <>
26 | Infrastructure as Code (IaC) will now be front and center in your Rails project folder by using the AWS Serverless Application Model (SAM). Easily create serverless Resources like S3 Buckets, EventBridge Rules, IAM Roles and more. Leverage SAM's CLI to create/update AWS Resources and your container images.
27 | >
28 | ),
29 | },
30 | ];
31 |
32 | function Feature({Svg, title, description}) {
33 | return (
34 |
Event-driven and deeply integrated within AWS, Lambda allows your Rails architecture to be completely reimagined atop fully managed infrastructure resources like Aurora, SQS, S3, CloudWatch, IAM, and much more. Using Lamby can help your engineering teams learn to "program the cloud".