RubyでAWS Lambda関数を書いてみよう!初心者向け実践ガイド
AWS Lambdaを使えば、オーバーヘッドを最小限に抑えながらスケーラブルな関数を構築できます。Railsアプリ全体を作成・ホスト・保守する代わりに、Lambda関数を活用すれば、個々のイベントに対して独立して応答する仕組みを簡単に実現できます。本記事では、AWS初心者のあなたを、自分自身のRuby製Lambda関数を書けるレベルまで導きます。
Lambdaは、サーバーを管理することなく、イベントに反応してコードを実行できるサービスです。このイベント駆動型アーキテクチャにより、コードが実際に稼働している時間にのみ課金され、アイドル状態の間は費用が発生しません。LambdaはS3バケットからファイルが削除されたときに処理を実行するなど、AWSエコシステム内のイベントへの応答として使われることが最も一般的ですが、AWS API Gatewayと組み合わせてAPIとして機能するよう設定することも可能です。
Lambdaは、Cronジョブのような時間ベースのタスク自動化や、イベントへの応答に利用できます。その用途は、DynamoDBなど他のAWSサービスと連携したデータ処理から、スケーラブルなAPIの構築まで多岐にわたります。例えば、Amazonのドキュメントにある以下の図は、モバイルクライアントがHTTPリクエストを送信し(おそらくデータベースへのCRUD操作のため)、API Gatewayがリクエストを対応するLambda関数へルーティングし(RailsがHTTPリクエストをコントローラへルーティングするのとよく似ています)、その関数がビジネスロジックを実行してDynamoDBと通信することでリクエストを完了させる、シンプルなアーキテクチャを示しています。

コードはコンテナ内で実行されるため、Amazonのインフラストラクチャは、関数が使用されていないときには自動的に一種のスリープモードに移行させます。新しいリクエストが届くと、コンテナはコールドステート( cold start)から起動する必要があり、実行時間が最大2000msほど増加することがあります。これはレスポンス時間という観点でサービス品質を低下させるだけでなく、追加のコストも発生させます。そのため、ユーザーへのメール送信やUIイベントへの応答といった時間に敏感なタスクにLambdaを使用すると、ボトルネックになる可能性があります。この問題を緩和するには、AWS CloudWatchで定期的なリクエストをスケジュールして関数を「ウォーム」状態に保つ方法がありますが、ホスティングコストは増加します。
なぜAWS Lambdaを使うのか
Amazon Web Services(AWS)は世界で最も人気のあるクラウドコンピューティングサービスです。個人開発者でも手軽に使えるシンプルさを持ちながら、世界最大級の企業のインフラとして耐えうるパワーとスケーラビリティを兼ね備えています。
AWS Lambdaは、Amazonが提供する「サーバーレスコンピュートサービス」の一つで、イベントに反応したときにだけコードを実行できます。これによりオーバーヘッドが削減され、サーバー全体をホストしたりアプリケーション全体を構築したりすることなく、API呼び出しなどに対してプログラム的に反応できるようになります。
適切なユースケースにおいて、このサーバーレスアーキテクチャは大幅なコスト削減をもたらします。料金は「リクエスト単価」と「コンピュート時間の単価」で計算されます。各月最初の100万リクエストを超えた分については、100万リクエストあたり0.20ドルプラス、関数が消費したコンピュート時間1GB秒あたり0.0000166667ドルとなります。ご想像の通り、この従量課金制のおかげで、小規模なサービスをLambda上で極めて安価に運用できながら、同じレートで無限にスケールする選択肢も維持できます。
Ruby開発者も、このクラウドサービスをステートレスな形でAPI呼び出しや他のAWSイベントに対応する手段として活用することで、大きなメリットを得られます。
AWSトライアルアカウントの作成
AWSは非常に寛大な無料利用枠を提供しており、AWS Lambdaでは毎月100万件の無料リクエストと、最大320万秒のコンピュート時間が含まれています!すでにアカウントをお持ちの方はこのステップをスキップできますが、アカウント作成はとても簡単です。
サインアップページにアクセスし、必要事項を入力して始めましょう。

続けて、アカウントタイプや連絡先情報などの詳細入力を求められます。また、無料枠を超える利用に備えてクレジットカード/デビットカード情報の登録が必要です。本記事のような簡単なLambdaの使い方は無料枠に含まれますが、うっかり超额請求が心配な方は、予算(Budget)を設定して利用量を管理し、予期しない請求を防ぐこともできます。
RubyでLambda関数を作成する
登録が完了したら、「サービス」メニューから「コンピューティング(Compute)」にカーソルを合わせ、「Lambda」を選択します。

Lambdaコンソールに入ったら(「開始方法」ボタンを押す必要があるかもしれません)、空の関数リストと「Create Function(関数の作成)」というオレンジ色のボタンが表示されるはずです。お察しの通り、私たちはそのオレンジ色の「Create Function」ボタンを押します。

次に「Author from Scratch(一から作成)」を選びます。Ruby用のテンプレート関数はまだ用意されていませんし、ゼロから作業するのが学習にも最適だからです。
関数には適切な名前を付け、作業したいRubyのバージョンを選択してください。筆者は有名なプログラミング問題にちなんで「FizzBuzz」という名前を付けました。
ナビゲーションペイン内のlambda_function.rbファイルをダブルクリックすると、ソースコードが表示されます。
関数はあらかじめlambda_handlerという名前で書かれています。初期状態のまま呼び出すと、下記のように「Hello From Lambda!」というテキストを含む200レスポンスを返します。

テストトリガーでLambda関数を試す
冒頭で説明したように、Lambda関数はさまざまな方法でトリガーできます。最も一般的なのはAPI呼び出し経由ですが、これにはAWS API Gatewayのセットアップが必要で、本記事の範囲を少し超えます。とはいえ、API GatewayはLambdaと組み合わせることで、最小限の設定と無限のスケーラビリティでAPIを構築できる優れたサービスです。
幸いなことに、関数コンソールからAPI呼び出しをシミュレートするのはそれほど難しくなく、しかもテストイベントはすでに用意されています。
関数概要の下にはツールバーがあり、現在「Code(コード)」が選択されています。前のスクリーンショットのように、「Code」の隣に「Test(テスト)」というタブがあります。「Test」を選択すると、コードソースの代わりにテストコンソールが表示されます。

事前設定されたテストイベントはJSONオブジェクトで、Lambda関数にeventオブジェクト(関数のパラメータ)として渡されます。API Gateway経由でエンドポイントを呼び出す場合、これはリクエストボディに相当します。
プレースホルダーのLambda関数はeventを読み取らないため、ボディに何を送っても問題ありません。そのため、そのままオレンジ色の「Invoke(呼び出し)」ボタンを押して進めましょう。
関数が正しくセットアップされていれば、「Execution Succeeded(実行に成功しました)」という緑色のボックスが表示されます。展開すると、関数からのJSONレスポンスを確認できます。
FizzBuzzを書いてみよう
Lambda関数が正しく動作することを確認できたので、次は独自のRubyコードでカスタマイズしてみましょう。この例では、有名なFizzBuzz問題に応答するLambda関数を作ります。FizzBuzzは面接でよく出題される定番問題で、お題は次のようなものです。
1から50までの数字を出力するプログラムを書きなさい。ただし、3の倍数のときは数字の代わりに「Fizz」を、5の倍数のときは「Buzz」を出力すること。また、3と5両方の倍数の場合は「FizzBuzz」を出力すること。
Lambda関数のコードを、筆者のFizzBuzz解答に置き換えてください。
require 'json'
def lambda_handler(event:, context:)
max_val = event['max_val']
textResponse = ''
1.upto(max_val) do |i|
if i % 5 == 0 and i % 3 == 0
textResponse += "FizzBuzz"
elsif i % 5 == 0
textResponse += "Buzz"
elsif i % 3 == 0
textResponse += "Fizz"
else
textResponse += i.to_s
end
end
{ statusCode: 200, body: JSON.generate(textResponse) }
end
これは通常のFizzBuzzを少しアレンジしたものです。単純に50までループするのではなく、イベントで送られてきた数値までループします。eventオブジェクトはハッシュ(辞書)のように渡されるため、event['max_val']と書けばmax_valキーに対応する値を取得できます。さらに、結果を出力する代わりに文字列へ追記していき、最後にJSONオブジェクトとして返却しています。
次に、必ずオレンジ色の「Deploy(デプロイ)」ボタンを押して、新しいコードでLambda関数を更新してください。
解答を書いてデプロイしたら、テストコンソールに戻りましょう。テストイベントを変更して、max_valキーと値のペアだけを渡すようにします。次のような形になります:

JSONはシンプルにこうです。
{
"max_val": 70
}
最後に「Invoke」を押してテストを実行しましょう!結果を展開すると、関数が入力を読み取り、FizzBuzz問題の結果を返していることが確認できます。
開発をもっと快適にするには
Webコンソールでの作業は学習目的には便利ですが、それだけに制限されるのは悪夢でしょう。AWS Lambdaでの開発で最も人気のある方法の一つは、CLI(Command Line Interface=コマンドラインインターフェース)の利用です。
IAMロールで適切な権限を作成したら、マシンにCLIをインストールし、認証情報を設定します。そうすれば、お好みのIDEでローカル開発しながらLambda CLIで関数をテストし、コマンドラインから変更をデプロイできるようになります。
もう一つの人気の開発手法は、Serverlessのようなフレームワークを使うことです。Serverlessは、AWS特有の煩雑な設定作業の多くを引き受けてくれます。関数にAPI Gatewayが必要な場合のセットアップもその一つです。さらにServerlessはロギングの強化、Ruby Gem管理の簡素化、CI/CDの設定も可能にし、パイプラインに基づいてリポジトリから自動デプロイできるようになります。
Serverlessや類似フレームワークを使わない場合、Ruby Gemを含めるにはいくつかの手順が必要です。関数をフォルダ形式に拡張し、ルートディレクトリに.bundle/configファイルを作成して、インストールしたGemの格納場所をbundlerに教えるための以下の初期化コードを記述します。
---
BUNDLE_PATH: "vendor/bundle"
その後、CLIでbundle addを使って必要なGemを追加し、コード内で直接requireすればOKです。
AWS Lambdaの制限事項
おめでとうございます!これであなたは初めてのRuby製AWS Lambda関数を書き上げました。以前はRubyでAPIを運用する現実的な解決策は、Railsアプリを丸ごと作成することであることがほとんどでした。今や、エンドポイントを一つずつ作成し、フルアプリケーションの肥大化をすべて回避できます。Lambdaはマイクロ秒単位で課金されるため、迅速なソリューションには驚くほど安価です。さらに、このクラウドサービスを活用すれば、低コスト運用を保ちながら驚異的な速さでスケールできます。Netflixがピーク時に安定して動作でき、常に最大容量のサーバー帯域にお金を払わずに済んでいるのは、まさにAWSのおかげです。
しかし、多くのメリットがある一方で、AWS Lambdaは万能の解決策ではありません。単体ではAPIとして機能せず、ステート(状態)の扱いにも制限があります。Lambda関数の実行時間は15分以内、メモリは6GBまでという制約があります。また、Lambda関数のテストはやや難しく、別環境にインフラ全体を再現する必要が生じることも少なくありません。
24時間365日稼働し続ける必要のないアプリや機能なら、Lambdaは良い選択肢かもしれません。しかし、何らかの状態を保持する必要がある場合や、AWSエコシステム外のデータを更新する必要がある場合は、Lambdaは不向きです。Lambdaはデフォルトで同時実行1,000接続に制限されているため、常により多くの利用が見込まれるアプリケーションでは信頼性が大きく損なわれます。要するに、Lambdaは永続的な状態を必要としない、短命なイベント駆動型の自動化タスクに最も適しています。
Lambda関数は、特にあなたのようなRuby開発者の手にかかれば、非常に強力なツールになり得ます。
-
Rubyのメソッド入門:defキーワードで独自のメソッドを定義する方法
Rubyにおける「メソッド」とは、特定の目的のためにひとまとめにされた、1行以上のRubyコードのことです。 このコードのまとまりには名前が付けられており、一度定義してしまえば、同じコードを何度も書いたりコピー&ペーストしたりすることなく、必要なときにいつでも再利用できます。 メソッドの主な役割 メソッドの目的は、大きく分けて以下のようなものがあります。 情報を取得する オブジェクトを変更・生成する データをフィルタリング・整形する 具体例 例1: Arrayオブジェクトに対するsizeメソッドは、配列内の要素数を返します(情報の取得)。 例2: popメソッドは、配列から最後の要素を取り
-
Ruby 2.6の新機能9選|コード例でわかる注目ポイントを徹底解説
Ruby 2.6には、開発者の生産性を高める新しい機能やパフォーマンス改善が多数盛り込まれています。 本記事では、Ruby 2.6で導入された9つの注目新機能を、実際のコード例とともにわかりやすく紹介します。最新のRuby動向をキャッチアップしたい方は、ぜひ最後までご覧ください。 1. 無限Range(Endless Range) Ruby 2.5以前でもFloat::INFINITYを使えば終端のない範囲を表現できましたが、Ruby 2.6ではさらに直感的な記法が使えるようになりました。 新しい無限Rangeは次のように書きます。 (1..) 通常のRangeが(1..10)のように終端