AWS STUDY NORE
Laravel 8 + Bref 1.0 執行 artisan 與排程工作
artisan 命令與排程是我們在開發與部署 Laravel 專案時,非常會需要用到的功能,當我們利用 Bref 把 Laravel 部署到 AWS Lambda 後,又該怎麼用呢?
經過「用 Bref 1.0 讓 Laravel 8 serverless 起來」這一篇的實驗後,我們已經可以利用 Bref 1.0 把 Laravel 8 專案部署到 AWS Lambda 上去,實現了把 Laravel 專案無伺服器化,在這個紀錄中,我們也嘗試了引用額外的 PHP redis extension layer,讓我的專案可以存取 Amazon ElastiCache。
不過,一個 Laravel 專案的功能通常不僅於此,例如我們經常需要自己開發 artisan 命令以及排程執行一些定期要執行的工作,當 Laravel 專案被部署到 AWS Lambda 後,一樣能執行 artisan 命令跟排程工作嗎?
現在就讓我們來研究看看 Bref 怎麼解決上面這兩個問題,接下來的紀錄會是接續「用 Bref 1.0 讓 Laravel 8 serverless 起來」這邊所做出來的 Laravel 8 專案,還沒有試過的人可以先參考這篇文章。
執行 Artisan 命令
在上一篇文章中,當我們用 phpbref/laravel-bridge 這個 package 建立了適用於 Laravel 的 serverless.yml 設定檔後,可以在這個設定檔中發現除了屬於網站的那個 function 設定外,還多了以下這一段,看名稱應該也能猜到這是做給 artisan 用的:
登入 AWS Lambda 主控台去看看,也可以發現除了 laravel-dev-web
這個 Lambda function 外,還有一個叫做 laravel-dev-artisan
也被建立起來。但這要怎麼用呢?Bref 關於這部分,有兩個相關的文件:
- https://bref.sh/docs/runtimes/console.html
- https://bref.sh/docs/frameworks/laravel.html#laravel-artisan
根據文件,要執行命令的話要透過 vendor/bin/bref
這個命令,其用法為:
$ vendor/bin/bref cli <function-name> -- <command>
但根據我測試的結果,是要指定 AWS region 的,其指令格式如下:
$ cli [--region REGION] [--profile PROFILE] [--] <function> [<arguments>...]
我部署的 region 是 ap-northeast-1,且我的本機有設定 profile,所以我實際測試成功的指令是:
$ vendor/bin/bref cli --region ap-northeast-1 --profile ashley \
laravel-dev-artisan --
這個 laravel-dev-artisan
就是我們部署到 AWS Lambda 的 function 名稱,如果有改過 serverless.yml,那這邊記得要換掉,而這個函式就是取代了 artisan,而 --
後面就是要加我們所要執行的 artisan 指令。
例如我們想要執行 php artisan migrate
的話,就會變成是:
$ vendor/bin/bref cli --region ap-northeast-1 --profile ashley \
laravel-dev-artisan -- migrate
不過,我的專案目前會出現一個錯誤:
PHP Warning: PHP Startup: Unable to load dynamic library '/opt/bref-extra/redis.so'...
這是因為我在上一篇文章中做的實驗,有用到 redis,所以也必須要在 laravel-dev-artisan
這個 Lambda function 中引用 ${bref:extra.redis-php-74}
這個 layer 才行,把這個引用加上去後,serverless.yml 就變成:
設定完成後,一樣用 serverless deploy
部署一下,完成後再執行一次指令,登登登登,是不是很熟悉的畫面!
為了測試,我很簡單地在 routes/console.php
裡寫了一個命令,寫完後一樣再部署一次:
// routes/console.php
Artisan::command('bref:test {content}', function ($content) {
$this->info("This is echo from Bref: {$content}!");
});
部署完成後,本地跟 Lambda 那邊都執行看看:
$ php artisan bref:test "Bref is good"
This is echo from Bref: Bref is good!
$ vendor/bin/bref cli --region ap-northeast-1 --profile ashley laravel-dev-artisan -- bref:test "Bref is good"
This is echo from Bref: Bref is good!
啟動排程
不知道大家在開發 Laravel 專案時,是怎麼使用排程的,我自己的經驗是蠻常用排程來呼叫自己開發的命令,例如先用 artian command 寫一個掃描未付款訂單並且寄送付款提醒,然後再用排程去設定每天固定某一個時間執行之類的。
剛好我們已經做好了一個 bref:test
的命令,那就延續這個經驗,在 app/Console/Kernel.php
加上以下設定:
protected function schedule(Schedule $schedule)
{
$schedule->command('bref:test "Bref is good!"')
->everyMinute();
}
在一般的 Linux 主機部署中,我們會在 cron 中加入以下設定:
* * * * * cd /path-to-your-project && php artisan schedule:run >> /dev/null 2>&1
問題是用 Bref 部署到 AWS Lambda 要怎麼做呢?Bref 的文件中有兩個地方提到這一部分:
因為在 Laravel 專案中,執行排程工作的時候,是利用 cron 每分鐘都去執行一次 schedule:run
,因此我試著在原本的 artisan 這邊加上文件中提供的設定:
部署後,可以在 Amazon CloudWatch Logs 這個 /aws/lambda/laravel-dev-artisan
Log groups 看到執行的結果:
serverless.yml 的這段設定其實是利用了 Amazon CloudWatch Events 的 Rules 來達成排程,登入 AWS CloudWatch 的主控台後,也能看到有一個 rule 被建立出來:
看起來蠻順利的,不過在過程中,我試著在 input 中想要達成可以執行 bref:test "Bref is good"
,但沒有成功,在 input 這裡實際上是對應到 Amazon CloudWatch Rule 中的 Configure input
設定,規定是用 JSON 格式:
可是 serverless.yml 是一個 YAML 檔,因此在 input 的設定上必須要用一個單引號包著一組雙引號,而在 artisan 的輸入是一個包含空白的字串時,也需要用單引號或雙引號包起來,我試著用 \
來跳脫,但是著幾種組合都沒有成功,如果有朋友知道怎麼做的,可以分享一下~
結語
繼上一篇文章中的 Laravel 專案,這次更近一步地試著在 AWS Lambda 的環境下執行 artisan 命令,並且用 Amazon CloudWatch Events Rule 取代 cron 來定期執行 schedule:run
以達成 Laravel 的排程工作。
看來一個 Laravel 專案常用的功能應該都能透過 Bref 在 AWS Lambda 下做到了。不過,在 phpbref/laravel-bridge 中特別有一個蠻大的篇幅在討論怎麼用 AWS SQS 來當 Laravel 的 Queue,再找個時間來試試看,看起來也很好玩~
參考資料
- [系列文] 用 Bref 1.0 讓 Laravel 8 serverless 起來
- phpbref/laravel-bridge
- https://bref.sh/docs/runtimes/console.html
- https://bref.sh/docs/frameworks/laravel.html#laravel-artisan
- https://bref.sh/docs/web-apps/cron.html
- https://bref.sh/docs/function/cron.html
- Tutorial: Schedule AWS Lambda Functions Using CloudWatch Events