インフラチームの小川です。普段は Web サービスにおけるクラウドインフラの構築/運用をしています。
いまホットなのは構想だけが存在しているデータレイクの構成案を具現化するプロジェクトで、特に Web アプリケーション側から DWH の情報をいかに使いやすく取得できるかを、日々考えています。
前職から変わらずインフラエンジニアですが、裁量の大きさが前職の比ではなく、さすがベンチャーといえます。自由に動ける分責任も大きいため、冷や汗をかくことも多いですが、このような環境が成長を後押ししてくれている実感があります。
さて、そんな弊社では昨年 Symfony 3.4 へのアップデートを行いました。
同時に、 PHP ライブラリである AWS SDK for PHP も重い腰を上げ v2 から v3 へアップデートしたのですが、その際に色々とハマってしまいました。
ハマった中には、AWS 公式のアップグレードガイドに言及のないケースもちらほらとありました。あのとき味わったつらみをこの記事で供養してやりたいと思います。
前提
- PHP 7.2.8
- Symfony 3.4.17
- AWS SDK for PHP 2.8.29 -> 3.69.7
基本: AWS 公式のアップグレードガイド
https://docs.aws.amazon.com/ja_jp/sdk-for-php/v3/developer-guide/getting-started_migration.html
基本的にはここに書かれている通りにソースを修正していけばよいはずです。
記載されている主な変更点を抜き出してみました。
- プロジェクトの依存関係が更新
- インスタンス化に
region
とversion
が必須化 - インスタンス化はファクトリメソッドではなく
new
になった - クライアント設定オプションが変更
Aws\Sdk
オブジェクトがAws\Common\Aws
の置き換えとして導入
- 一部 API の結果に ラップ要素 が追加
- AWS の
Enum
クラスが削除 - きめ細やかな例外クラスが削除。ルート例外クラスをキャッチしなければいけなくなった
enableFacades()
の廃止- 結果の返却がイテレーターからページネーターに変更
- 多くの 高レベルの抽象化が変更 (日本語でおk)
以上のことだけを意識すれば良い...わけではありませんでした。
ここに苦戦
AwsException で必須のコンストラクタ引数が増えて苦戦
エラーメッセージ
ArgumentCountError: Too few arguments to function Aws\Exception\AwsException::__construct(), 1 passed in /var/app/current/.../hoge.php on line 147 and at least 2 expected
解説
Aws 系の Exception をインスタンス化するとき、これまでは以下のように引数は最低 1 つだけあれば大丈夫でした。
$sesException = new SesException($errorMessage);
しかし、v3 からは新たに Aws\CommandInterface
が必須の引数となりました。
construct ( string $message, Aws\CommandInterface $command, array $context = [], Exception $previous = null )
https://docs.aws.amazon.com/aws-sdk-php/v3/api/class-Aws.Exception.AwsException.html#_construct
このときは SesException のスタブオブジェクトを作成したかったため、適当な Aws\Command
オブジェクトを渡すことでエラーを回避しました。
// テストコードなので引数は適当 $sesException = new SesException($errorMessage, new Aws\Command('test'));
SesException::setExceptionCode() が廃止されて苦戦
エラーメッセージ
Error: Call to undefined method Aws\Ses\Exception\SesException::setExceptionCode()
解説
文字通り、SesException::setExceptionCode()
が v3 で消滅しました。またもや、親クラスの AwsException の仕様変更のようです。
setter だけでなく、getter 系メソッドも以下のように名前を変えたので要注意です。
v2 | v3 |
---|---|
getExceptionCode() | getAwsErrorCode() |
getExceptionType() | getAwsErrorType() |
getRequestId() | getAwsRequestId() |
SES の ResponseMetadata から RequestId が取得できなくなって苦戦
エラーメッセージ
SES の sendEmail()
を行ったあと、v2 では以下のようにしてリクエスト ID を取得していました。
$response = $sesClient->sendEmail($parameters); $requestId = $response->get('ResponseMetadata')['RequestId'],
しかし、v3 では $requestId
の値が空っぽになってしまいました。
AWS のサポートに質問したところ、
AWS SDK PHP v2 の sendEmail では Guzzle\Service\Resource\Model オブジェクトを返します。
V3 では sendEmail は AWS\Result オブジェクトを返します
キー名が ResponseMetadata ではなく、@metadata に変更されております
と返事をいただきました。すなわち、
$response = $sesClient->sendEmail($parameters); $requestId = $response->get('@metadata')['headers']['x-amzn-requestid']
と書く必要があります。こうすることで、v3 でも RequestId を得ることができるようになりました。
なお、上記は正常系を想定しているので、sendEmail()
に失敗したときは SesException
の getAwsRequestId()
を使ってください。
deleteObjects() に Delete Parameter が必須となって苦戦
エラーメッセージ
InvalidArgumentException: Found 1 error while validating the input provided for the DeleteObjects operation: [Delete] is missing and is a required parameter
解説
S3 で複数のオブジェクトを削除する際に使う deleteObjects()
に、 Delete
パラメータが必須となりました。
これまでは、削除したいオブジェクトの配列を Objects
の値として渡せばよかったのですが、それをさらに Delete
で wrap する必要があります。
$s3->deleteObjects([ 'Bucket' => 'hoge-bucket', 'Objects' => [ [ 'Key' => 'path/to/hoge' ], [ 'Key' => 'path/to/fuga' ], ], ])
$s3->deleteObjects([ 'Bucket' => 'hoge-bucket', 'Delete' => [ 'Objects' => [ [ 'Key' => 'path/to/hoge' ], [ 'Key' => 'path/to/fuga' ], ], ], ])
さいごに
細かな仕様変更がちらほらとありました。
弊社の場合、上記をふまえて影響調査をしたところ、思っていた以上に修正箇所が発生してしまい、結構な時間をロスしてしまいました。
PHP SDK をバージョンアップする際は、期間に余裕をもって的確に行うことが大切です。