web-dev-qa-db-ja.com

AWS Elastic BeanstalkでLaravel Schedulingをセットアップして使用するにはどうすればよいですか?

シナリオ

LaravelとElastic Beanstalkのかなり新しいユーザーである私は、ほとんどの人がそうであるように、すぐに操作をスケジュールする必要があることに気づきました。

過去には、これに常に単純なcrontabスケジューリングを使用していました。だから今私は質問のリストの前に立った:

  • Laravel crontabを使用したコードを実行するにはどうすればよいですか?
  • Elastic Beanstalk環境でcrontabを設定するにはどうすればよいですか?

これらの質問に対する個々の答えを見つけることはそれほど難しくありませんでした。それらを組み合わせて実際にすべてを機能させることは、しかし、少しトリッキーであることがわかりました。そのため、これを適切に機能させるのに苦労している他の人のために、ここでソリューションを共有することにしました。


環境

  • Laravel 5.6
  • PHP 7.1
12
Niklas

TL; DR:

回答の最後にある実際の_.ebextentions_構成を参照してください。


環境

  • Laravel 5.6
  • PHP 7.1

Crontabを使用してLaravelコードを実行するにはどうすればよいですか?

この質問への回答はもちろん最も明白であり、Laravelに少しでも慣れていれば、きっとその回答を知っています。 Scheduling

Laravel Schedulingとは、ドキュメントでそれを自分で読むことができるためです。

しかし、私たちが持ち歩く必要がある重要なことは、Laravel=スケジューリングは、ドキュメントで説明されているように、実行にcrontabを使用することです。

_* * * * * php /path-to-your-project/artisan schedule:run >> /dev/null 2>&1
_

これは次に私たちを導き、そしてもう少しトリッキーな質問です...


Elastic Beanstalk環境でcrontabを設定するにはどうすればよいですか?

一見すると、この質問に対する答えは非常に簡単に思えるかもしれません。 AWS Knownledge Centerでこれを見つけました: Elastic Beanstalk環境のEC2インスタンスでcronジョブを作成するにはどうすればよいですか?

ここでは、.ebextentionsを使用してElastic Beanstalk EC2マシンでcronジョブをセットアップする方法について説明します。つまり、目的のcronジョブを配置するディレクトリ_/etc/cron.d/_に新しいファイルを作成します。

このディレクトリ内のファイルは、crontabによってrootユーザーとして処理されます。以下にコメントしたように、私が侵入したいくつかの落とし穴があります。

_files:

    # The name of the file should not contain any dot (.) or dash (-), this can
    # cause the script not to run. Underscore (_) is OK.
    "/etc/cron.d/mycron":

        # This permissions is important so that root user can run the script.
        mode: "000644"

        # As the file is run by the root user it needs to be the owner of the file.
        owner: root

        # For consistency it's a good idea to have root as the group aswell.
        group: root

        # NOTE: We need to explicitly tell the cron job to be run as the root user!
        content: |
            * * * * * root /usr/local/bin/myscript.sh 

# There need to be a new line after the actual cron job in the file.
_

これらすべてのトラップをクリアした後は、Laravel cronジョブを上からスケジュールします。これは次のようになります。

_files:
    "/etc/cron.d/schedule_run":
        mode: "000644"
        owner: root
        group: root
        content: |
            * * * * * root php /path-to-your-project/artisan schedule:run >> /dev/null 2>&1
_

ただし、これはほとんどの場合実際には機能しません。これは、LaravelスケジューラがENV変数にアクセスできず、データベースの設定を著しく変更してはならないためです。

私はこれに対する答えをここに見つけました: 取得方法Laravel AWS Elastic Beanstalk Cronでタスクスケジューリングが機能

それで、ジョージ・ベニッシュに大きな叫びをあげました。これを共有してくださった皆さんに敬意を表します!

それで、この最後のパズルのピースで、最終的にセットアップを正しく機能させることができました:


ワーキングソリューション

ファイル構造:

_[Project root]
    |-- .ebextensions
    |        |-- cronjob.config
_

cronjob.config:

_files:
    "/etc/cron.d/schedule_run":
        mode: "000644"
        owner: root
        group: root
        content: |
            * * * * * root . /opt/elasticbeanstalk/support/envvars && /usr/bin/php /var/www/html/artisan schedule:run 1>> /dev/null 2>&1

commands:
    remove_old_cron:
        command: "rm -f /etc/cron.d/*.bak"
_

Laravel AWS Elastic Beanstalkでのスケジューリング!

Elastic Beanstalkの主要な機能の1つは、必要に応じて自動スケーリングしてサーバーを追加できることです。Laravel Scheduling: Running 1つのサーバー上のタスク

多くの場合、複数のサーバーでcronジョブを実行したくありません。たとえば、メールを送信するためのスケジュールされたコマンドがある場合、それらを複数回送信することは望ましくありません。

注:これには、ドキュメントに記載されているように、キャッシュエンジンとしてmemcachedまたはredisを使用する必要があります。そうでない場合は、AWSサービス Elasticache をご覧ください。

注2:onOneServer()を使用する場合、name()メソッドを使用して、スケジュールされたタスクに名前を付ける必要があります(前にonOneServer())を呼び出します。そのようです:

_$schedule->command('my:task')
    ->name('my:task')
    ->daily()
    ->onOneServer();
_
17
Niklas

より簡単な方法は、新しい定期的なタスク機能を使用することです。 cronジョブに.ebextensionsを使用すると、複数のマシンで同じジョブが実行されたり、自動スケーリングで他の競合状態が発生する可能性があります。

cron.yamlで定義されたジョブは、ワーカー環境によってのみロードされ、一度に1台のマシン(リーダー)によってのみ実行されることが保証されています。重複がないことを確認するために、Nice同期メカニズムがあります。ドキュメントから:

Elastic Beanstalkはリーダー選出を使用して、ワーカー環境のどのインスタンスが定期的なタスクをキューに入れるかを決定します。各インスタンスは、Amazon DynamoDBテーブルに書き込むことでリーダーになることを試みます。成功する最初のインスタンスはリーダーであり、リーダーのステータスを維持するために引き続きテーブルに書き込む必要があります。リーダーがサービスを停止すると、別のインスタンスがすぐにその役割を果たします。

単一または複数のワーカーのcronを作成する

プロジェクトのルートにcron.yamlを配置します。

version: 1
cron:
  - name: "schedule"
    url: "/worker/schedule"
    schedule: "* * * * *"

考慮すべきことの1つは、Beanstalkの定期的なタスクは、アプリケーションのURLにHTTP POSTリクエストを送信するように設計されていることです。これにより、実行するジョブがトリガーされます。これは、 SQSでキューを管理する方法。

Laravelの場合

Laravel=の場合、具体的には、スケジュールされた各ジョブを処理するためのルートとコントローラーを作成できます。しかし、より良いアプローチは、Laravelのスケジューラーを使用し、毎分呼び出す単一のルートを用意することです。

このパッケージはこれらのルートを自動的に作成します https://github.com/dusterio/laravel-aws-worker

権限のトラブルシューティング

CodePipelineからデプロイをトリガーするときにDynamoDBのLeader Table作成権限で問題が発生している場合は、CodePilelineサービスロールにdynamodb:CreateTableが必要なためです。手順については、これらを確認してください StackOverflow質問

公式Elastic Beanstalk定期タスクドキュメント

1
Arian Acosta