avram / aws-cron-job

Laravel命令,仅让单个EC2实例在AWS云托管上运行schedule:run定时任务

v0.4.2 2024-01-26 00:13 UTC

README

这是一个Laravel 5/6/7/8/9的包,它允许在您的ElasticBeanstalk负载均衡的AWS设置中仅在一个EC2实例上运行定时任务。

对于不同的Laravel版本,请使用相应的包版本

  • Laravel 5: ^0.1
  • Laravel 6: ^0.2
  • Laravel 7: ^0.3
  • Laravel 8, 9 & 10: ^0.4

问题

在典型的AWS负载均衡环境中,所有EC2实例都完全相同,它们都将运行任何配置的定时任务(如果通过.ebextensions文件夹配置)。在某些情况下这可能没问题,但可能导致定时任务运行多次,这可能会成为一个问题,例如您的系统可能会发送多次相同的电子邮件通知。

AWS解决方案

AWS建议在.ebextensions文件夹中使用leader_only标志为定时任务,这将仅在第一个部署的实例上设置定时任务。这很好,直到负载均衡器介入,创建一个新非领导者实例,然后决定不需要额外的实例并杀死一个实例,可能是运行时间最长的实例,这可能是您的领导者实例;并且由于leader_only仅在部署期间应用,您将没有领导者实例,也不会运行定时任务。

针对此问题还有更多解决方案,但其中大多数都需要在AWS端进行额外设置。其中一些甚至建议您只为定时任务设置另一个EC2实例。在某些情况下这可能没问题,但我不太喜欢这样做。

AWS Cron Job

此包提供了一种简单的方法,可以从单个EC2实例触发定时任务,而无需更改您的AWS设置。它将简单地从您的AWS账户中获取单个AWS EB环境的所有当前运行实例,按字母顺序排序,然后检查当前实例ID是否与列表中的第一个相同。当实例发生变化时,列表会动态更改,因此您无需担心这一点!

为了提高性能,此包默认将实例列表缓存5分钟,但您可以更改此设置。此外,由于实例ID永远不会更改(实例可以更改但它们的ID不能,至少不是自动的),当前实例ID将永远缓存。所有内容都将在同一实例上本地缓存(file缓存驱动程序)。

安装

只需通过composer要求即可

composer require avram/aws-cron-job

Laravel 5.5(及更高版本)应在您使用composer安装此包时自动发现并启用服务提供程序。对于旧版本,您必须手动将服务提供程序添加到您的config/app.php

'providers' => [

	// ...

	Avram\AwsCronJob\Providers\AwsCronJobServiceProvider::class,
	
],

设置

AWS凭证

此包依赖于AWS PHP SDK,它将自动从AWS_ACCESS_KEY_IDAWS_SECRET_ACCESS_KEY环境变量中获取您的API密钥和秘密密钥,因此最好在环境中定义这些值。但是,您也可以将这些值硬编码(见下文)。

配置

此包提供了一个配置文件,您必须与以下内容一起发布

php artisan vendor:publish --provider="Avram\AwsCronJob\Providers\AwsCronJobServiceProvider"

之后,您可以在config/awscronjob.php中设置包

<?php

return [
    'connection'        => [
        'region'  => env('AWS_REGION', 'ca-central-1'),
        'version' => env('AWS_API_VERSION', 'latest'),
//        'credentials' => [
//            'key'    => env('AWS_ACCESS_KEY_ID','my-access-key-id'),
//            'secret' => env('AWS_SECRET_ACCESS_KEY','my-secret-access-key'),
//        ],
    ],
    'aws_environment'   => env('AWS_CRON_ENV', 'app-production'),
    'skip_environments' => env('AWS_CRON_SKIP_APP_ENV', 'local'),
    'run_on_errors'     => env('AWS_CRON_RUN_ON_ERRORS', true),
    'cache_time'        => env('AWS_CRON_CACHE_TIME', 5),
    'cache_enabled'     => env('AWS_CRON_CACHE_ENABLED', true),
];
  • connection AWS区域和API版本(默认情况下将从您的环境变量中获取凭证)
  • aws_environment AWS环境名称(用于通过环境名称标记筛选实例)
  • skip_environments 要跳过的 Laravel 应用环境列表,以逗号分隔,并自动运行定时任务(默认:local
  • run_on_errors 当与 AWS 服务器通信发生错误时,是否运行定时任务(默认:true
  • cache_time 应该缓存所有实例列表多长时间(以分钟为单位,默认:5
  • cache_enabled 是否缓存实例列表和实例 ID(默认:true

由于每个环境至少有一个 aws_environment,因此最好不要过度修改已发布的配置文件,而是直接在您的 Elasticbeanstalk 控制台中设置以下环境变量

  • AWS_ACCESS_KEY_ID
  • AWS_SECRET_ACCESS_KEY
  • AWS_REGION
  • AWS_CRON_ENV
  • AWS_API_VERSION(可选)
  • AWS_CRON_SKIP_APP_ENV(可选)
  • AWS_CRON_RUN_ON_ERRORS(可选)
  • AWS_CRON_CACHE_TIME(可选)

注意:您的 AWS IAM 用户必须具有 ec2:Describe* 权限才能访问您的实例列表。为了以防万一,我给我的用户分配了 arn:aws:iam::aws:policy/AmazonEC2ReadOnlyAccess 策略。

使用方法

简单来说,不要像这样运行您的定时任务

php artisan schedule:run

...而是改为

php artisan aws:schedule:run

...就这样! ;)