1. Home
  2. PHP
  3. Laravel
  4. LaravelのコマンドスケジューラでDBのバックアップを行う定時処理(Cron)を構築する

LaravelのコマンドスケジューラでDBのバックアップを行う定時処理(Cron)を構築する

  • 公開日
  • 更新日
  • カテゴリ:Laravel
  • タグ:PHP,Laravel,Command
LaravelのコマンドスケジューラでDBのバックアップを行う定時処理(Cron)を構築する

PHP フレームワークで WEB アプリケーションを構築しているのであれば、cron に登録し定時処理を行うプログラムもそのフレームワーク内で書くべきです。そうする事によって、データベースなどの設定情報が散らばってしまう事を防げますし、フレームワーク内に定時処理のソースがある事で管理も楽になります。

という事で今回は、Laravel のコマンドスケジューラを使い、Cron に登録して動かす、いわゆる定時処理を実装していきます。「データベースのバックアップ」を例に進めていきたいと思います。

Contents

  1. 開発環境
  2. Command クラスの生成
  3. Command クラスの書式
  4. 処理の記述
  5. Command クラスの登録
  6. 処理をスケジュールに登録
  7. cron へスケジューラを登録
  8. 二重起動の防止ロック

開発環境

今回の開発環境に関しては以下の通りです。

  • Linux CentOS 7
  • Apache 2.4
  • MySQL 5.7
  • PHP 7.1/7.2
  • Laravel

Laravel のバージョンについては、5.6/5.5/5.4/5.3 にて動作確認済みです。

Laravel のルートディレクトリを「laravel/」とします。

Command クラスの生成

まずは処理を記述する為の Command クラスを生成します。
laravel ディレクトリに移動し、以下の artisan コマンドを叩きます。

# laravel ルートディレクトリへ移動
cd /path/to/projectroot/laravel

# 処理を記述するファイルの生成
php artisan make:command BackupDatabaseCommand --command="command:backupdb"

捕捉すると、

  1. artisan コマンドの「make:command 」で Command クラスを生成
  2. 引数にクラス名を指定
  3. command オプションを付け、ファイル生成時に $signature へ値を入力している。

となります。(※3に関しては後述します。)

[demo@localhost laravel]$ php artisan make:command BackupDatabaseCommand --command="command:backupdb"
Console command created successfully.

コマンドを叩くと、laravel/app/Console/ 直下に Commands ディレクトリが生成され、その中に BackupDatabaseCommand.php ファイルが作成されます。

laravel
├── app
│   ├── Console
│   │   ├── Commands
│   │   │   └── BackupDatabaseCommand.php
│   │   └── Kernel.php

Command クラスの書式

生成した Command クラスを開くと、デフォルトでは以下のような記述となっています。

laravel/app/Console/Commands/BackupDatabaseCommand.php
<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;

class BackupDatabaseCommand extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'command:backupdb';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Command description';

    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct()
    {
        parent::__construct();
    }

    /**
     * Execute the console command.
     *
     * @return mixed
     */
    public function handle()
    {
        //
    }
}

上から説明していきます。

protected $signature = 'command:backupdb';

コンソールコマンドの名前を指定しています。
この部分は、ファイルを生成した時に command オプションで渡した文字列が格納されています。
そして、この文字列を artisan コマンドから渡す事で、処理が実行される事になります。
「backupdb 」がこの処理の識別子で、「command:」は、artisan コマンド上でのグルーピングを表しています。

protected $description = 'Command description';

コンソールコマンドの説明を記述します。
多くの Command クラスを作る場合は、ここは書いておくとより良いです。

public function __construct()
{
    parent::__construct();
}

見ての通りのコンストラクタです。
初期値設定など行いたい場合はここへ記述出来ます。

public function handle()
{
   //
}

ここにメインの処理を記述していきます。

処理の記述

では、生成した BackupDatabaseCommand.php を開き、データベースのバックアップを行う処理を記述していきます。

<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;

class BackupDatabaseCommand extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'command:backupdb';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Command description';

    protected $db_host;
    protected $db_user;
    protected $db_pass;
    protected $db_name;
    protected $store_path;

    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct()
    {
        parent::__construct();

       $this->db_host = env('DB_HOST');      // DBホスト
        $this->db_user = env('DB_USERNAME');  // DBユーザ
        $this->db_pass = env('DB_PASSWORD');  // DBパスワード
        $this->db_name = env('DB_DATABASE');      // バックアップ対象スキーマ
        $this->store_path = '/tmp';           // 保存先ディレクトリ

    }

    /**
     * Execute the console command.
     *
     * @return mixed
     */
    public function handle()
    {
        // ファイル名
        $file_name = sprintf('%s.sql', date('YMDHis'));
        // ファイルフルパス
        $file_path = sprintf('%s/%s', $this->store_path, $file_name);

        $command = sprintf(
            'mysqldump --single-transaction -h %s -u %s -p%s %s > %s',
            $this->db_host,
            $this->db_user,
            $this->db_pass,
            $this->db_name,
            $file_path
        );

        exec($command, $output, $ret);
    }
}

mysqldump しているだけの、シンプルなものです。
protected でメンバ変数を宣言し、コンストラクタで初期値設定、そして handle メソッドにデータベースのバックアップ処理を記述します。

ちなみに補足ですが、MySQL5.7 ではデフォルトでコマンド内でのパスワード直書きを許容していないので、その場合は別途あれこれする必要があります。

Command クラスの登録

処理を記述したら、Command クラスが使えるように登録を行います。

laravel/app/Console/Kernel.php
protected $commands = [
    //
];

// ↓ ここに記述

protected $commands = [
    \App\Console\Commands\BackupDatabaseCommand::class,
];

登録した事により、artisan コマンドで手動実行も可能になりました。
laravel ルートディレクトリから以下を叩くと実行されます。

php artisan command:backupdb

一度コマンドを叩き、正常に動作するかを確認しておきましょう。

処理をスケジュールに登録

いよいよ、作った処理をスケジュールへ登録します。現段階では手動での実行のみですが、スケジュールに登録する事によって、定時処理として動作させる事が出来るようになります。

Kernel.php を開き、schedule メソッドへ以下のように記述します。

laravel/app/Console/Kernel.php
protected function schedule(Schedule $schedule)
{
    // 毎日深夜12時に実行
    $schedule->command('command:backupdb')->daily();
}

ここでは、
「command:backupdb を毎日、深夜0時に実行する」
という記述になっています。
尚、その他の記述方法としては以下になります。

  • cron('* * * * * *');
    • cron と同じ記法で記述する
  • everyMinute();
    • 毎分
  • everyFiveMinutes();
    • 5 分毎
  • everyTenMinutes();
    • 10 分毎
  • everyFifteenMinutes();
    • 15 分毎
  • everyThirtyMinutes();
    • 30 分毎
  • hourly();
    • 1 時間毎
  • hourlyAt(23);
    • 毎時 23 分
  • daily();
    • 毎日夜 0 時
  • dailyAt('18:45');
    • 毎日 18:45
  • twiceDaily(4, 20);
    • 毎日 4:00 と 20:00 時
  • weekly();
    • 毎週
  • monthly();
    • 毎月
  • monthlyOn(5, '19:00');
    • 毎月 5 日の 19:00
  • quarterly();
    • 四半期ごと
  • yearly();
    • 毎年実行
  • timezone('America/New_York');
    • タイムゾーン設定

cron へスケジューラを登録

最後に、cron へ laravel スケジューラを登録します。
laravel スケジューラ用に cron設定ファイルを作成し、その中へ記述します。

# cron設定ファイルの置き場所へ移動
cd /etc/cron.d

# laravel スケジューラの作成・記述
vim laravel_schedule
###################################################
* * * * * php /var/www/html/project_root/laravel/artisan schedule:run >> /dev/null 2>&1
###################################################

上記の記述で laravel スケジューラが毎分実行され、その都度、実行するべきタスクがあれば実行させてくれます。

尚、cron の稼働確認は「/var/log/cron 」で確認できますので、以下コマンドなど、適当に叩いて確認すると良いです(エラーはロギングされません)

# tail コマンドでログを watch する
tail -f /var/log/cron

# tail コマンドでログの最新 10 件を表示する
tail -n 10 /var/log/cron

二重起動の防止ロック

例えば毎分やそれに近いような、頻繁に実行を行う定時処理を動かしている場合に、もし次の実行までに前の処理が終わらなかったら処理が二重にかぶって動作してしまいます。これが溜まってしまうと WEB サーバが落ちたりデータの整合性が取れなくなったりと、悲惨な事になりかねません。

Laravel のタスクスケジューラでは、withoutOverlapping() メソッドをチェインする事で、処理を起動しようとした際に前に処理がまだ動いている場合は待機してくれます。

laravel/app/Console/Kernel.php
protected function schedule(Schedule $schedule)
{
    // 5分毎に実行
    $schedule->command('command:backupdb')->everyFiveMinutes()->withoutOverlapping();
}

まとめ

以上で作業は完了となります。
cron の設定ファイルって、動かすものが増えると記述が多くなり、 あとで見返すとごちゃごちゃしていて至極煩雑なんですが、laravel スケジューラの場合は、cron に記述するのはたったの1行だけで良いのでとても楽です。
あとは今回の手順の通りに Command クラスを生成し、スケジュールに登録するだけで実行される。 とても便利な機能です。
実行日時などを確認する際も、いちいちサーバへ入らなくてもローカルの laravel ソースを確認すればよいのですから、手間も省けますね。
トータルで便利なので、是非試してみてください。

Author

rito

  • Backend Engineer
  • Tokyo, Japan
  • PHP 5 技術者認定上級試験 認定者
  • 統計検定 3 級