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

时间:2018-06-29 07:55:07

标签: laravel amazon-web-services cron elastic-beanstalk laravel-5.6

场景

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

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

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

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


环境

  • Laravel 5.6
  • PHP 7.1

4 个答案:

答案 0 :(得分:7)

TL; DR:

请在答案末尾查看.ebextentions的有效配置。


环境

  • Laravel 5.6
  • PHP 7.1

如何使用crontab运行Laravel代码?

这个问题的答案当然是最明显的,如果您甚至不熟悉Laravel,您肯定知道答案:Scheduling

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

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

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

将我们带到下一个,还有一个棘手的问题……


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

乍一看,这个问题的答案似乎很简单。我在AWS知识中心发现了这一点:How do I create a cron job on EC2 instances in an Elastic Beanstalk environment?

在这里,他们描述了如何使用.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.

一旦我们清除了所有这些陷阱,就该从上方开始进行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

尽管如此,但这在大多数情况下还是行不通的。。这是因为Laravel Scheduler无法访问您的ENV变量,并且必须明显不能访问您的数据库设置。

我在这里找到了答案:How to Get Laravel Task Scheduling Working on AWS Elastic Beanstalk Cron

向GeorgeBönnisch大喊大叫;我向您致敬,谢谢您的分享!

因此,通过拼图的最后一部分,我终于能够使设置正常运行:


工作解决方案

文件结构:

[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"

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

由于Elastic Beanstalk的关键功能之一是它可以在需要时自动缩放并添加更多服务器,因此您可能想看看Laravel Scheduling中的新功能:Running Tasks On One Server

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

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

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

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

答案 1 :(得分:2)

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

cron.yaml中定义的

Job仅由Worker环境加载,并保证一次只能由一台计算机(领导者)运行。它具有良好的同步机制,以确保没有重复。从文档中:

Elastic Beanstalk使用领导者选举来确定您的工作人员环境中的哪个实例将定期任务排队。每个实例都尝试通过写入Amazon DynamoDB表来成为领导者。成功的第一个实例是领导者,并且必须继续写入表以保持领导者状态。如果领导者退出服务,另一个实例将很快取代它。

为一个或多个工人创建Cron

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

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

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

对于Laravel

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

此软件包将为您自动https://github.com/dusterio/laravel-aws-worker

创建那些路线

权限疑难解答

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

Official Elastic Beanstalk Periodic Tasks Docs

答案 2 :(得分:0)

在AWS ECS中,我们可以在不将cron添加到容器的情况下使用

https://github.com/spatie/laravel-cronless-schedule

这是您可以启动无时间表的方式:

php artisan schedule:run-cronless

答案 3 :(得分:0)

这是针对 docker 用户的,对此有一些问题,因此认为值得发布。

需要将 cron 添加到服务器上的 schedule_run 文件中。但是,即使您将 container_name 添加到 Dockerrun.aws.json 文件,它也会将其更改为该文件以及一些额外信息,因此您无法使用正常的服务名称来运行 cron。

因此,使用 $(docker ps -qf name=php-fpm) 其中 name 是容器名称的一部分,它将返回容器的 ID。我的容器名为 php-fpm

这是我的工作文件 (.ebextensions/01-cron.config)。

files:
"/etc/cron.d/schedule_run":
    mode: "000644"
    owner: root
    group: root
    content: |
        * * * * * root docker exec -t $(docker ps -qf name=php-fpm) sh -c "php artisan schedule:run" >> /var/log/eb-cron.log 2>&1

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

注意:这个cron第一次运行容器的时候没有启动。由于我的示例中的 cron 每分钟都在运行,因此它在第二次运行时没有太大关系,容器已启动并正常工作。