AWS STUDY NORE

Laravel 8 + Bref 1.0 執行 artisan 與排程工作

artisan 命令與排程是我們在開發與部署 Laravel 專案時,非常會需要用到的功能,當我們利用 Bref 把 Laravel 部署到 AWS Lambda 後,又該怎麼用呢?

Azole (小賴)

--

經過「用 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 用的:

serverless.yml

登入 AWS Lambda 主控台去看看,也可以發現除了 laravel-dev-web 這個 Lambda function 外,還有一個叫做 laravel-dev-artisan 也被建立起來。但這要怎麼用呢?Bref 關於這部分,有兩個相關的文件:

根據文件,要執行命令的話要透過 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.yml with redis-php

設定完成後,一樣用 serverless deploy 部署一下,完成後再執行一次指令,登登登登,是不是很熟悉的畫面!

artisan

為了測試,我很簡單地在 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 這邊加上文件中提供的設定:

schedule

部署後,可以在 Amazon CloudWatch Logs 這個 /aws/lambda/laravel-dev-artisan Log groups 看到執行的結果:

Amazon CloudWatch Log Groups

serverless.yml 的這段設定其實是利用了 Amazon CloudWatch Events 的 Rules 來達成排程,登入 AWS CloudWatch 的主控台後,也能看到有一個 rule 被建立出來:

Amazon CloudWatch Event 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,再找個時間來試試看,看起來也很好玩~

參考資料

--

--

Azole (小賴)

As a passionate software engineer and dedicated technical instructor, I have a particular fondness for container technologies and AWS.