Laravel9がステータスコード429を返す問題とその対策

はじめに

とある問題が発生し、ログを調べたところ、Laravel 9のAPIが見慣れないステータスコード429を返していました。

この記事では、ステータスコード429とは何か、どのような状況で発生するのか、そしてどのように対処すればよいのかを解説します。

ステータスコード429とは?

HTTPステータスコード「429 Too Many Requests」は、クライアントが一定期間内に許可されたリクエストの数を超過した場合に返されるエラーです。このエラーは、サーバーの負荷を軽減し、DoS攻撃や過剰なAPIアクセスからシステムを守るための防御手段として機能します。

Laravelではこの機能を「レート制限」で実装しており、これによってAPIやリソースへの過剰なアクセスを防ぐことができます。

参考

Laravelでのレート制限の仕組み

Laravelでは、特定のAPIルートやリソースに対して、一定時間内に許可されるリクエスト数を制限する「レート制限」が提供されています。この機能により、過剰な負荷を避け、安定したAPI提供が可能となります。制限に達した場合、クライアントにはHTTPステータスコード「429 Too Many Requests」が返されます。

Laravelのレート制限は、デフォルトでthrottleミドルウェアによって制御されます。たとえば、app/Http/Kernel.phpで以下のように定義されています。

'api' => [
    // \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
    'throttle:api',
    \Illuminate\Routing\Middleware\SubstituteBindings::class,
],

この’throttle:api’は、APIルートに対してデフォルトのレート制限を適用するもので、通常1分間に60リクエストが許可されています(ただし、バージョンや設定によって異なる場合があります)。

Laravelでのステータスコード429の対策

1. レート制限の調整

デフォルトのレート制限が厳しすぎる場合、これを緩和することができます。throttleミドルウェアによるレート制限は、アプリケーションの要件に合わせて簡単に調整できます。

たとえば、APIルートに対して1分間に60リクエストを許可していた設定を、1分間に100リクエストに変更したい場合は、app/Http/Kernel.phpで以下のように設定を変更します。

'api' => [
    'throttle:100,1',  // 1分間に100リクエストに緩和
    \Illuminate\Routing\Middleware\SubstituteBindings::class,
],

この設定では、1分間に100リクエストが許可されるようになっています。throttleの第1引数は最大リクエスト数、第2引数は時間(分)を表します。

2. カスタムレート制限の設定

より柔軟なレート制限を実現したい場合、カスタムのレート制限を設定することが可能です。例えば、特定のユーザーに対して異なるレート制限を適用したり、特定のエンドポイントでのみ制限を変更したりできます。

カスタムレート制限を設定するには、RouteServiceProvider.phpで以下のように編集します。

    /**
     * Configure the rate limiters for the application.
     *
     * @return void
     */
    protected function configureRateLimiting()
    {
        RateLimiter::for('api', function (Request $request) {
            return Limit::perMinute(100)->by(optional($request->user())->id ?: $request->ip());
        });
    }

この例では、APIエンドポイントに対して1分間に100リクエストの制限が設定されています。byメソッドは、ユーザーIDが利用可能な場合はユーザーIDに基づいて制限を適用し、それがない場合はクライアントのIPアドレスに基づいて制限を適用します。これにより、異なるユーザーやIPごとに独立したレート制限が管理されます。

さらに、ユーザーの役割や時間帯、特定のリクエストタイプに応じて異なる制限を設けることも可能です。これにより、例えば管理者は高いレート制限を持ち、一般ユーザーには標準的な制限を設ける、といった柔軟な運用が実現できます。

まとめ

ステータスコード「429 Too Many Requests」は、Laravelのレート制限により発生します。デフォルト設定では、通常1分間に60回以上のリクエストを送信するとこのエラーが返されますが、これらの制限は簡単にカスタマイズできます。

レート制限はAPIの安定運用にとって重要な機能です。負荷を軽減し、DoS攻撃を防ぐための対策として活用することで、システム全体のパフォーマンスを維持できます。必要に応じてレート制限を緩和したり、特定の条件に合わせたカスタマイズを行い、最適な設定を目指しましょう。

cdk deployでサービスリンクロールのエラーが発生したとき

cdk deployを実行した際に、サービスリンクロールのエラーが発生しました。

Resource handler returned message: “Invalid request provided: CreateCluster Invalid Request: Unable to assume the service linked role.”。

このエラーは、AWS ECSクラスターの作成時にサービスリンクロールを引き受けることができなかったことが原因です。
具体的には、サービスリンクロール (Service-Linked Role) が存在しないため、クラスターの作成に失敗しています。

Amazon ECS のサービスリンクロールの使用 – Amazon Elastic Container Serviceによると、

ほとんどの場合、サービスにリンクされたロールを手動で作成する必要はありません。AWS Management Console、AWS CLI、または AWS API でクラスターを作成したり、サービスを作成または更新したりすると、Amazon ECS によってサービスにリンクされたロールが自動的に作成されます。

とあるように、通常はサービスリンクロールは自動的に作成されます。

しかし、今回のように初回のcdk deploy時にエラーが発生する場合があります。
これは、おそらくサービスリンクロールの作成に時間がかかるためです。

この場合、以下の手順で対処できます。

  1. エラーが発生したら、一度デプロイを中止します。
  2. 数分待ってから、再度cdk deployを実行します。

試しにもう一度cdk deployを実行すると、今度は成功しました。

初回のデプロイ時にのみエラーが発生することがあるため、この現象に遭遇した場合は、少し待ってから再度デプロイを試みると良いでしょう。

この方法でエラーを回避できることを確認しましたので、同じ問題に直面した場合の参考にしてください。

Play ConsoleでAndroidアプリを非公開にできないとき

Play Consoleのアプリの詳細設定画面で、アプリの公開状況を「非公開」に変更できない問題が発生しました。

アプリの公開状況を「非公開」に変更するには、Play Console ヘルプの「アプリを非公開にする」に記載されている条件を満たす必要があります。

  • 最新のデベロッパー販売/配布契約に同意していること。
  • 対応が必要なエラー(コンテンツのレーティング質問票に回答していない、アプリのターゲットユーザーとコンテンツに関する詳細情報を提供していない、など)がアプリにないこと。
  • 非公開にするアプリで管理対象の公開が有効になっていないこと。

今回は、管理対象の公開が有効になっていたため、「非公開」に変更できませんでした。

以下の手順で管理対象の公開をオフにすることで、アプリを非公開に変更できるようになります。

  1. 「公開の概要」の「管理対象の公開をオフにする」をクリックします。
  2. 「管理対象の公開:オフ」を選択し、「保存」をクリックします。

これで、詳細設定画面でアプリの公開状況を「非公開」に変更できるようになります。

macOSにaws_completerを導入してAWS CLIのコマンド補完を有効にする

macOSにaws_completerを導入し、AWS CLIのコマンド補完を有効にする手順を紹介します。

手順

(1) AWS CLIのインストール

まず、Homebrewを使用してAWS CLIをインストールします。

% brew install awscli

(2) aws_completerのパスを確認する

まず、aws_completerのパスを確認します。

% which aws_completer
/opt/homebrew/bin/aws_completer

(3) シェルを識別する

現在使用しているシェルを確認します。

% echo $SHELL
/bin/zsh

(4) コマンド補完を有効にする

次に、コマンド補完を有効にするために、~/.zshrcファイルに以下の設定を追加します。

autoload bashcompinit && bashcompinit
autoload -Uz compinit && compinit
complete -C '/opt/homebrew/bin/aws_completer' aws

(5) 変更を反映する

設定を反映するために、プロファイルを現在のセッションに再ロードします。

% source ~/.zshrc

(6) コマンド補完の確認する

最後に、AWS CLIのコマンド補完が有効になっていることを確認します。

% aws s<TAB>
s3                              sesv2
s3api                           shield
s3control                       signer

参考