如何在AWS Elastic Beanstalk上设置和使用Laravel计划?

Nik*_*las 7 cron amazon-web-services laravel amazon-elastic-beanstalk laravel-5.6

情境

作为Laravel和Elastic Beanstalk的新用户,我很快发现自己需要像我们大多数人一样计划操作。

过去,我一直为此使用简单的crontab调度。所以现在我站在一系列问题之前:

  • 如何使用crontab运行Laravel代码?
  • 如何在我的Elastic Beanstalk环境中设置crontab?

找到这些问题的个别答案并不难。将它们组合起来并真正使所有功能正常工作却有些棘手,这就是为什么我决定在这里与其他努力使它正常工作的人分享解决方案的原因。


环境

  • Laravel 5.6
  • PHP 7.1

Nik*_*las 12

TL; DR:

请参阅.ebextentions答案末尾的工作配置。


环境

  • Laravel 5.6
  • PHP 7.1

如何使用crontab运行Laravel代码?

当然,这个问题的答案是最明显的,如果您即使最不熟悉Laravel,也肯定知道答案:安排时间

因为您可以自己在文档中阅读有关内容,所以我不会为您解释Laravel Scheduling的精彩之处。

但是我们需要带走的关键是,Laravel Scheduling使用crontab来执行,如文档中所述:

* * * * * php /path-to-your-project/artisan schedule:run >> /dev/null 2>&1
Run Code Online (Sandbox Code Playgroud)

这将我们带入下一个问题,还有一些棘手的问题...


如何在我的Elastic Beanstalk环境中设置crontab?

乍一看,这个问题的答案似乎很简单。我在AWS知识中心中找到了这一点:如何在Elastic Beanstalk环境中的EC2实例上创建cron作业?

在这里,他们描述了如何使用.ebextentions在Elastic Beanstalk EC2计算机上设置cron作业。简而言之,它所做的是/etc/cron.d/在我们想要的cron作业所在的目录中创建一个新文件。

然后,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.
Run Code Online (Sandbox Code Playgroud)

一旦我们清除了所有这些陷阱,就该从上方开始进行Laravel Scheduling 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
Run Code Online (Sandbox Code Playgroud)

不过,在大多数情况下,这实际上是行不通的。这是因为Laravel Scheduler将无法访问您的ENV变量,并且必须明显不能访问您的数据库设置。

我在这里找到了答案:如何在AWS Elastic Beanstalk Cron上进行Laravel任务调度

乔治·伯尼施(GeorgeBönnisch)大喊大叫;先生,我向您致敬!

因此,通过这最后一个难题,我终于能够使设置正常运行:


工作方案

文件结构:

[Project root]
    |-- .ebextensions
    |        |-- cronjob.config
Run Code Online (Sandbox Code Playgroud)

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"
Run Code Online (Sandbox Code Playgroud)

在AWS Elastic Beanstalk上使用Laravel调度时的提示!

由于Elastic Beanstalk的关键功能之一是它可以自动缩放并在需要时添加更多服务器,因此您可能想看看Laravel调度:在一台服务器上运行任务中的新功能。

在许多情况下,您不希望您的cron作业在多个服务器上执行。例如,如果您有预定的发送电子邮件的命令,则您不希望多次发送电子邮件。

注意:这要求您使用memcached或redis作为缓存引擎,如文档中所述。如果没有,请看一下AWS服务Elasticache

注意2:使用时onOneServer(),必须使用name()方法为计划的任务命名(调用之前onOneServer())。像这样:

$schedule->command('my:task')
    ->name('my:task')
    ->daily()
    ->onOneServer();
Run Code Online (Sandbox Code Playgroud)

  • @DhrumilBhankhar 显然,当创建新的 Schedule_run 时,旧的会获得“.bak”后缀。`remove_old_cron` 是删除旧的(顾名思义) (3认同)
  • 是的,至少在写这篇文章的时候是这样。如果我没有命名它,我就会收到错误。也许这在5.7或5.8版本中有所改变,尚未检查。 (2认同)
  • ebextensions 配置中的 `remove_old_cron` 命令部分上面是什么?是否有旧 crom 生成的 .bak 文件需要我们清理?您能详细说明一下它的用处吗? (2认同)

Ari*_*sta 5

一种更简单的方法是使用新的定期任务功能。使用.ebextensionsfor cron 作业可能会导致多台机器运行相同的作业或自动缩放的其他竞争条件。

中定义的作业cron.yaml仅由 Worker 环境加载,并保证一次仅由一台机器(领导者)运行。它有一个很好的同步机制来确保没有重复。来自文档:

Elastic Beanstalk 使用领导者选举来确定工作线程环境中的哪个实例对定期任务进行排队。每个实例都尝试通过写入 Amazon DynamoDB 表来成为领导者。第一个成功的实例是领导者,并且必须继续写入表以维持领导者状态。如果领导者停止服务,另一个实例很快就会取代它的位置。

为单个或多个 Worker 创建 Cron

放置cron.yaml在项目的根目录中:

version: 1
cron:
  - name: "schedule"
    url: "/worker/schedule"
    schedule: "* * * * *"
Run Code Online (Sandbox Code Playgroud)

需要考虑的一件事是,在 Beanstalk 中,定期任务旨在向应用程序中的 URL 发出 HTTP POST 请求,从而触发您要运行的作业。这与它使用 SQS 管理队列的方式类似。

对于 Laravel

特别是对于 Laravel,您可以创建路由和控制器来处理每个计划的作业。但更好的方法是使用 Laravel 的调度程序并拥有一条每分钟调用的路由。

该包将自动为您创建这些路由https://github.com/dusterio/laravel-aws-worker

权限疑难解答

如果您在从 CodePipeline 触发部署时遇到 DynamoDB 创建领导表权限的问题,这是因为 CodePileline 服务角色需要dynamodb:CreateTable. 有关说明,请查看这些StackOverflow 问题

官方 Elastic Beanstalk 定期任务文档