Laravel:メンテナンスモード

Date:

Share post:

バックエンド(Laravel)の更新作業中はアクセスを拒絶したい場合があります。
Webサーバアプリ(Apache等)を止めてしまうという方法もありますが、Laravelではメンテナンス状態をソフト的に実現するメンテナンスモードというものがあります。

メンテナンスモードを開始する方法は簡単で、以下のようなコマンドを実行するだけです。

php artisan down

メンテナンスモードを解除するコマンドは以下になります。

php artisan up

メンテナンスモードでは全てのアクセスに対してHTTPステータスコードとして503が返されます。
503は「Service Unavailable(サービスが一時的に過負荷やメンテナンスで使用不可能)」という意味なので納得です。

弊社では昨今はフロントエンドとバックエンドの分離を進めており、フロントエンドはNuxtで実装、両者の間はAPIで接続するようにしています。
このようなケースでもメンテナンスモードは有効です。

例えば、APIにおいて「api/test」なるアクションが存在するとします。
「routes/api.php」の内容は以下の通り。

Route::get('test', \App\Http\Controllers\TestController::class)->name('test');

上記アクションに対して以下のテストケースが成立します。

$path = route('test');

$response = $this->json('get', $path);
$response->assertStatus(200);

$this->artisan('down'); // メンテナンスモード開始

$response = $this->json('get', $path);
$response->assertStatus(503);

$this->artisan('up'); // メンテナンスモード解除

$response = $this->json('get', $path);
$response->assertStatus(200);

なお、特定のキーワード(バイパストークン)を指定した場合はメンテナンスモードでもバックエンドの機能を使用できるようにすることも可能です。

具体的にはメンテナンスモード開始時にバイパストークンを指定します。

php artisan down --secret="hogehoge"

「–secret」オプションで指定しているのがバイパストークン(この場合は「hogehoge」)です。

このトークンを指定してメンテナンスモードのバックエンドを使用できるようにするためには、一旦当該ドメインにバイパストークンを指定してアクセスします。
この時、バイパスクッキー(laravel_maintenance)が設定されるため、以降同クッキーが設定された状態であればメンテナンスモードをバイパスして各種機能が使用できるようになります。

こちらもテストケースで確認してみましょう。

$path = route('test');

// メンテナンスモード開始(バイパストークンあり)
$this->artisan('down', ['--secret' => 'hogehoge']);

$response = $this->json('get', $path);
$response->assertStatus(503);

$response = $this->get('/hogehoge'); // バイパストークン指定
$response->assertStatus(302);

// バイパスクッキー(laravel_maintenance)取得
$cookieObjects = $response->headers->getCookies();
foreach ($cookieObjects as $cookieObject) {
    if ($cookieObject->getName() === 'laravel_maintenance') {
        $laravelMaintenanceVal = $cookieObject->getValue();
    }
}

$this->disableCookieEncryption();
$this->withCredentials();
$this->withCookies(['laravel_maintenance' => $laravelMaintenanceVal]);
$response = $this->json('get', $path);
$response->assertStatus(200);

大雑把に説明すると、以下のような流れになっています。

  • 最初にバイパストークンを指定してメンテナンスモードを開始
  • $pathへのアクセスが503でエラーとなることを確認
  • バイパストークンを指定してアクセス
  • バイパスクッキーを取得
  • バイパスクッキーを指定した$pathへのアクセスが正常終了することを確認

上記テストケースは成立します。

コマンド一発でメンテナンスモードを開始したり解除したりできるのは便利ですね。

(以下、蛇足ながら)
実は、上記テストケースにおいてバックエンドから戻されたクッキーを指定して所定のAPIを呼び出す処理の実現に意外に苦戦しました。

まず、レスポンス情報からクッキーの値を取得する方法に関する情報がネット上でもあまり見当たりませんでした。
わずかな情報と試行錯誤で上記のようなやり方で取得できることが確認できましたが。

また、取得したクッキーをjsonメソッドでのアクション呼び出し時に指定する方法も謎でした。
クッキーを指定する方法である「withCookies」に関する情報はネット上にもあるのですが、これだけだと正しく動作しません。
実はjsonメソッドでは「withCredentials」メソッドを実行しておかないとクッキーが有効になりません。
加えてクッキーは(ミドルウェアの設定次第ですが)一般的には暗号化されるようになっていると思いますが、バイパストークンに関しては暗号化されていないことが期待される模様で、暗号化を解除しておく必要があります。これを行っているのが「disableCookieEncryption」です。

上記のような操作を行うことでバックエンドから戻されたクッキーを指定してjsonメソッドの実行ができるようになるのですが、これらに関して説明されている記事をネット上では発見できませんでした。
このような使い方はあまりされないんでしょうかね?(あるいは探し方が悪いのか?)

Related articles

我流Flutter学習ステップ(6)スマホでの動作...

本シリーズ(?)の最初の投稿で書いた...

その「平均値」に意味はあるのか?

最近「平均」に関して思うところがあっ...

遅まきながら、Vagrant(Virtualbox...

前回は、pumaを常時起動のユーザーサ...