Upgrade to PRO for Only $50/Year—Limited-Time Offer! 🔥

S3操作の落とし穴から学ぶ Laravel File Storageと例外処理

S3操作の落とし穴から学ぶ Laravel File Storageと例外処理

2024/07/02
Fusic Tech Live Vol.20 〜PHPer CONNECT〜
https://fusic.connpass.com/event/317123/

mai miya

July 02, 2024
Tweet

More Decks by mai miya

Other Decks in Technology

Transcript

  1. ©Fusic Co., Ltd. 2 宮崎 真⾐ Miyazaki Mai HN: mai

    (@maimyyym ) ◉ I am - 管理栄養⼠(養成校卒業・資格保持のみ) - 元百貨店スタッフ(Beauty Counselor) - 2023年10⽉ Fusic⼊社 ◉ Skill - PHP / AWS / TypeScript / Python ◉ Comment - Tech Live初登壇です!うれしい! ⾃⼰紹介 はじめに 事業本部 技術創造部⾨ / エンジニア 株式会社Fusic
  2. ©Fusic Co., Ltd. 3 今⽇話すこと はじめに Laravel on FargateでのS3操作 Laravel

    Filesystemにおける例外処理 について経験して、学んで、考えてみた話
  3. ©Fusic Co., Ltd. 4 CONTENTS ⽬次 1. こんな構成・処理 2. Laravelのファイルシステム

    3. 困ったこと・その答え 4. 例外処理の話 / どうしたらよかったのか 5. まとめ
  4. ©Fusic Co., Ltd. 8 LaravelのStorageファサードで実装する こんな構成・こんな処理 try { Storage::disk("s3")->copy( $sourcePath,

    $distinationPath ); } catch (\Exception $e) { Log::error(''. $e->getMessage()); return redirect()->route(‘user.top’)->with(‘error’, ‘copy失敗'); } return redirect()->route('user.top')->with('success', 'copy成功'); Storageファサードは抽象化された Filesystemによって、ストレージの 種類によらずコピー等の操作を 簡単に実装できる。 Storage::disk(ʻs3ʼ)->copy($from, $to);
  5. ©Fusic Co., Ltd. 10 Flysystem Laravelのファイルシステム Laravelのファイルシステムは、Flysystemというライブラリを使⽤して 実装されている。 【 Flysystem

    とは?】 PHPのためのファイルストレージライブラリ。 異なるストレージドライバ(ローカル、S3、FTPなど)に対する ⼀貫したインターフェースを提供する。 ストレージシステムの種類を問わず、 コードを変更することなく簡単に切り替えることができる。
  6. ©Fusic Co., Ltd. 11 使い⽅ Laravelのファイルシステム 1. アダプタをインストールする 2. ファイルシステム設定(config/filesystems.php)

    3. 使う: composer require league/flysystem-aws-s3-v3 "^3.0" --with-all-dependencies 's3' => [ 'driver' => 's3’, 'key' => env('AWS_ACCESS_KEY_ID’), 'secret' => env('AWS_SECRET_ACCESS_KEY’), 'region' => env('AWS_DEFAULT_REGION’), 'bucket' => env('AWS_BUCKET’), 'throw’ => false, ] Storage::disk("s3")->xxx();
  7. ©Fusic Co., Ltd. 15 コピー処理ができていなかった 困ったこと・その答え 【やろうとしたこと】 S3に保存された画像ファイルのコピー操作や その他DB操作等を含む⼀連の処理 【結果】

    レスポンス:200OK しかし、S3のコピー処理だけができていない ※その他DB操作等の処理は全てできていた 《⼊⼒》 ↓ 処理A ↓ 処理B ↓ S3コピー処理 ↓ 《出⼒》 OK! OK! Failed…😰 200OK $request
  8. ©Fusic Co., Ltd. 16 コピー処理ができていなかった 困ったこと・その答え 【やろうとしたこと】 S3に保存された画像ファイルのコピー操作や その他DB操作等を含む⼀連の処理 【結果】

    レスポンス:200OK しかし、S3のコピー処理だけができていない ※その他DB操作等の処理は全てできていた 《⼊⼒》 ↓ 処理A ↓ 処理B ↓ S3コピー処理 ↓ 《出⼒》 OK! OK! Failed…😰 200OK $request コピーしたオブジェクトの 取得処理ができず、気づいた
  9. ©Fusic Co., Ltd. 17 考えたこと 困ったこと・その答え CPU使⽤率が⾼くなる… move() もできない! get()

    → put() だと うまくいく Filesystemの裏側の 処理に違いが? ロジックに問題が?
  10. ©Fusic Co., Ltd. 18 考えたこと 困ったこと・その答え CPU使⽤率が⾼くなる… move() もできない! get()

    → put() だと うまくいく Filesystemの裏側の 処理に違いが? ロジックに問題が? でも・・・ 裏側が複雑な実装だとは思えない! 【 copy() 】と【 get() → put() 】で ⼤きな差が出るとは思えない…
  11. ©Fusic Co., Ltd. 19 考えたこと 困ったこと・その答え CPU使⽤率が⾼くなる… move() もできない! get()

    → put() だと うまくいく Filesystemの裏側の 処理に違いが? ロジックに問題が? では、原因は何…?
  12. ©Fusic Co., Ltd. 21 { "Version": "2012-10-17", "Statement": [ {

    "Action": [ "s3:ListBucket", "s3:PutObject", "s3:GetObject", "s3:PutObjectAcl", "s3:GetObjectAcl", ], "Effect": "Allow", "Resource": "*" }, ] } 【正しくは…】 答えは・・・ 困ったこと・その答え ポリシー不⾜でした。 タスクロール { "Version": "2012-10-17", "Statement": [ { "Action": [ "s3:ListBucket", "s3:PutObject", "s3:GetObject", ], "Effect": "Allow", "Resource": "*" }, ] } 【現在】
  13. ©Fusic Co., Ltd. 22 答えは・・・ 困ったこと・その答え ドキュメントがあった。 またコンソール内のオブジェクトのコピー、カット、貼り付けを⾏う ためには、s3:PutObjectAcl および

    s3:GetObjectAcl アクションが必要 となります。 https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/userguide/example-policies-s3.html#iam-policy-ex3
  14. ©Fusic Co., Ltd. 23 S3のアクセスコントロールリスト(ACL) 困ったこと・その答え PutObjectAcl, GetObjectAclとは? 【Amazon S3のアクセスコントロールリスト(ACL)とは】

    バケットとオブジェクトへのアクセスを管理するもの。 各バケットとオブジェクトにはサブリソースとしてACLがアタッチされる。
  15. ©Fusic Co., Ltd. 24 S3のアクセスコントロールリスト(ACL) 困ったこと・その答え PutObjectAcl, GetObjectAclとは? 【Amazon S3のアクセスコントロールリスト(ACL)とは】

    バケットとオブジェクトへのアクセスを管理するもの。 各バケットとオブジェクトにはサブリソースとしてACLがアタッチされる。
  16. ©Fusic Co., Ltd. 25 ACL ACL S3のアクセスコントロールリスト(ACL) 困ったこと・その答え PutObjectAcl, GetObjectAclとは?

    ACL ACL 同じ状態を複製する=コピーという操作には オブジェクトとACLの両⽅を取得・保存する権限が必要 GetObject GetObjectAcl
  17. ©Fusic Co., Ltd. 28 copyメソッドの中⾝を⾒てみる 例外処理の話 / どうしたらよかったのか FilesystemAdapter.phpのcopyメソッドを⾒てみる public

    function copy($from, $to) { try { $this->driver->copy($from, $to); } catch (UnableToCopyFile $e) { throw_if($this->throwsExceptions(), $e); return false; } return true; } 私たちがコードとして書くストレージ操作と Flysystemを橋渡しするクラス
  18. ©Fusic Co., Ltd. 29 copyメソッドの中⾝を⾒てみる 例外処理の話 / どうしたらよかったのか FilesystemAdapter.phpのcopyメソッドを⾒てみる public

    function copy($from, $to) { try { $this->driver->copy($from, $to); } catch (UnableToCopyFile $e) { throw_if($this->throwsExceptions(), $e); return false; } return true; } 私たちがコードとして書くストレージ操作と Flysystemを橋渡しするクラス 返り値は true / false
  19. ©Fusic Co., Ltd. 30 copyメソッドの中⾝を⾒てみる 例外処理の話 / どうしたらよかったのか FilesystemAdapter.phpのcopyメソッドを⾒てみる public

    function copy($from, $to) { try { $this->driver->copy($from, $to); } catch (UnableToCopyFile $e) { throw_if($this->throwsExceptions(), $e); return false; } return true; } 私たちがコードとして書くストレージ操作と Flysystemを橋渡しするクラス 返り値は true / false $this->throwsExceptions() がtrueの時に例外を投げる
  20. ©Fusic Co., Ltd. 31 copyメソッドの中⾝を⾒てみる 例外処理の話 / どうしたらよかったのか throwsExceptions()を⾒てみる public

    function copy($from, $to) { try { $this->driver->copy($from, $to); } catch (UnableToCopyFile $e) { throw_if($this->throwsExceptions(), $e); return false; } return true; } protected function throwsExceptions(): bool { return (bool) ($this->config['throw'] ?? false); } config🤔
  21. ©Fusic Co., Ltd. 32 copyメソッドの中⾝を⾒てみる 例外処理の話 / どうしたらよかったのか つまり、copyメソッドはどのように例外を投げるのか public

    function copy($from, $to) { try { $this->driver->copy($from, $to); } catch (UnableToCopyFile $e) { throw_if($this->throwsExceptions(), $e); return false; } return true; } protected function throwsExceptions(): bool { return (bool) ($this->config['throw'] ?? false); } config[ʻthrowʼ] = 例外を投げる設定 がtrueであれば例外を投げ、 そうでなければfalseを返す
  22. ©Fusic Co., Ltd. 33 copyメソッドの中⾝を⾒てみる 例外処理の話 / どうしたらよかったのか 設定ファイルを⾒てみる 's3'

    => [ 'driver' => 's3’, 'key' => env('AWS_ACCESS_KEY_ID’), 'secret' => env('AWS_SECRET_ACCESS_KEY’), 'region' => env('AWS_DEFAULT_REGION’), 'bucket' => env('AWS_BUCKET’), 'throw’ => false, ] 【config/filesystems.php】 デフォルト設定 =falseのまま
  23. ©Fusic Co., Ltd. 34 copyメソッドの中⾝を⾒てみる 例外処理の話 / どうしたらよかったのか 呼び出し元を⾒てみる try

    { Storage::disk("s3")->copy( $sourcePath, $distinationPath ); } catch (\Exception $e) { Log::error(''. $e->getMessage()); return redirect()->route(‘user.top’)->with('error', 'copy失敗'); } return redirect()->route('user.top')->with('success', 'copy成功'); この処理結果を出⼒すると ”false ”だった。 例外をキャッチしていない
  24. ©Fusic Co., Ltd. 35 copyメソッドの中⾝を⾒てみる 例外処理の話 / どうしたらよかったのか 例外を投げる設定にする 's3'

    => [ 'driver' => 's3’, 'key' => env('AWS_ACCESS_KEY_ID’), 'secret' => env('AWS_SECRET_ACCESS_KEY’), 'region' => env('AWS_DEFAULT_REGION’), 'bucket' => env('AWS_BUCKET’), 'throw’ => true, ] 【config/filesystems.php】
  25. ©Fusic Co., Ltd. 36 copyメソッドの中⾝を⾒てみる 例外処理の話 / どうしたらよかったのか 再度、呼び出してみる try

    { Storage::disk("s3")->copy( $sourcePath, $distinationPath ); } catch (\Exception $e) { Log::error(''. $e->getMessage()); return redirect()->route(‘user.top’)->with('error', 'copy失敗'); } return redirect()->route('user.top')->with('success', 'copy成功'); 処理に失敗すると、 例外をキャッチするように!
  26. ©Fusic Co., Ltd. 37 Flysystem3.xの仕様 例外処理の話 / どうしたらよかったのか Laravel8までは例外を投げていた。 Laravel9で、Flysystemのバージョンが1.xから3.xに。

    伴って、ファイル操作の仕様が⼀部変更。 その⼀つが書き込み失敗時に例外を投げなくなったこと。 (代わりに、falseを返すように) https://laravel.com/docs/9.x/upgrade#flysystem-3
  27. ©Fusic Co., Ltd. 38 例外 vs false 例外処理の話 / どうしたらよかったのか

    仕組みは分かった。 例外を投げる設定をしていれば、確かに気づけた。 しかし、デフォルトはtrue / falseを返すだけ。 その思想は「アプリケーションを⽌めないこと」などが考えられる。 そもそもポリシーを知っていればよかった問題! テストフェーズで気づいたから成果物の挙動としては問題ない。 本当にそれでいいの?
  28. ©Fusic Co., Ltd. 39 例外 vs false 例外処理の話 / どうしたらよかったのか

    betterはどっち? 例外を投げる その場で失敗が分かるべき 詳細なエラーログを保存・通知したい falseを返す アプリケーションは⽌めない falseの場合の挙動ロジックを⽤意する
  29. ©Fusic Co., Ltd. 40 仕様と向き合い、仕様を定める 例外処理の話 / どうしたらよかったのか betterはどっち? 例外を投げる

    その場で失敗が分かるべき 詳細なエラーログを保存・通知したい falseを返す アプリケーションは⽌めない falseの場合の挙動ロジックを⽤意する ⼀つの正解はない
  30. ©Fusic Co., Ltd. 41 仕様と向き合い、仕様を定める 例外処理の話 / どうしたらよかったのか betterはどっち? 例外を投げる

    その場で失敗が分かるべき 詳細なエラーログを保存・通知したい falseを返す アプリケーションは⽌めない falseの場合の挙動ロジックを⽤意する ⾔語・フレームワークの 仕組みや仕様を知ること どうあるべきかを考える 前提
  31. ©Fusic Co., Ltd. 43 まとめ S3操作の落とし⽳から学ぶLaravel File Storageと例外処理 Laravelのストレージ操作はPHPのファイルストレージライブラリ”Flysystem”で抽象化されている Point

    01 S3のコピー処理においては、オブジェクトだけではなくACLを取得・保存する権限を付与する必要がある Point 02 Laravelのストレージ操作において、書き込み失敗時のデフォルトは「例外を投げず、falseを返す」 Point 03 フレームワークの仕様と向き合い、アプリケーションの仕様を定めることが⼤切 Point 04
  32. ©Fusic Co., Ltd. 44 Thank You We are Hiring! https://recruit.fusic.co.jp/

    ご清聴いただきありがとうございました