SQSからLambda上のLaravelを動かす

SQSへのQueue投入をトリガとしてLambda上のLaravelを叩けたら便利そうなので試してみた。

もし Laravel の SQS Queue を Lambda で処理したいのであれば [brefphp/laravel-bridge](https://github.com/brefphp/laravel-bridge) こちらを。

## 前提

Serverless Framework 導入が前提です。未導入であればこちらなどを参考に導入してください。

[Serverless Frameworkの使い方まとめ - Qiita](https://qiita.com/horike37/items/b295a91908fcfd4033a2)


## 今回の構成

sqsEvent.php が SQSから呼び出される本体。

SQS -> sqsEvent.php -> QueueController 

という流れ。

複数のQueueを扱いやすいよう、QueueController にキューの名称と同じアクション（今回の例は testSqs）を作ると自動的に呼び出されるような形で実装しました。

## 環境構築

カレントディレクトリへのLaravelのインストールと[Bref](https://bref.sh/)のインストール。すでに Laravelプロジェクトがある場合は ```composer require aws/aws-sdk-php``` の行から実行してください。

```bash
composer create-project --prefer-dist laravel/laravel .
composer require aws/aws-sdk-php
composer require bref/bref
vendor/bin/bref init
```

## serverles.yml と sqsEvent.php

test-app-*-queue という名称で lambda 関数作成する場合。

```serverless.yml
service: test-app

provider:
    name: aws
    region: ap-northeast-1
    runtime: provided

plugins:
    - ./vendor/bref/bref

functions:
    queue:
        handler: sqsEvent.php
        description: ''
        layers:
            - ${bref:layer.php-73}
        events:
          - sqs:
              # 既存のSQSキューを使う場合
              arn: arn:aws:sqs:ap-northeast-1:アカウントID/testSqs
              # 新規にSQSキューを作る場合
#              arn:
#                Fn::GetAtt:
#                  - PhpQueue
#                  - Arn
#
#resources:
#  Resources:
#    PhpQueue:
#      Type: AWS::SQS::Queue
#      Properties:
#        QueueName: testSqs
```

SQSから呼び出される sqsEvent.php（新規作成）。

```sqsEvent.php
<?php
/**
 * SQSとの連携動作
 */
declare(strict_types=1);
require __DIR__.'/vendor/autoload.php';
$app = require __DIR__ . '/bootstrap/app.php';

$kernel = $app->make(Illuminate\Contracts\Console\Kernel::class);
$kernel->bootstrap();

return function (array $event) {

    $controller = new App\Http\Controllers\QueueController;
    foreach($event['Records'] as $record) {
        if (preg_match("/:([^:]+)$/", $record['eventSourceARN'], $matches)) {
            $action = $matches[1];
            if (!method_exists($controller, $action)) {
                echo $record['eventSourceARN'] . " method not exists in QueueController.\n";
                echo json_encode($record);
                continue;
            }
            return $controller->$action($record['body']);
        } else {
            echo $record['eventSourceARN'] . " eventSourceARN error.\n";
            echo json_encode($record);
            continue;
        }
    }
};

````

Queueを処理するコントローラー app/Http/Controllers/QueueController.php

```app/Http/Controllers/QueueController.php
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class QueueController extends Controller
{
    //testSqsのQueueを受け取る
    public function testSqs($body)
    {
        // ここに処理を書く
        echo $body;
    }
}
```

## デプロイ＆実行

デプロイ

```bash
serverless deploy
```

Queueを登録して動作を確認しましょう。

```bash
 aws sqs send-message --queue-url https://sqs.ap-northeast-1.amazonaws.com/アカウントID/testSqs --message-body testtest
```

CloudWatch Logs で ```testtest``` という出力が確認できるはずです。

## ハマりどころ

1. S3にアクセスできない

[Brefのドキュメント](https://bref.sh/docs/frameworks/laravel.html#file-storage-on-s3)に記述があるが、config/filesystems.php の問題でそのままではアクセスできない。
s3 の設定に token の追加すればアクセスできるようになります。

```php
        's3' => [
            'driver' => 's3',
            'key' => env('AWS_ACCESS_KEY_ID'),
            'secret' => env('AWS_SECRET_ACCESS_KEY'),
            // この token の行を追加
            'token' => env('AWS_SESSION_TOKEN'),
            'region' => env('AWS_DEFAULT_REGION'),
            'bucket' => env('AWS_BUCKET'),
            'url' => env('AWS_URL'),
            'endpoint' => env('AWS_ENDPOINT'),
        ],
```