クラウドファンクションでサムネイル生成
FirebaseのCloud Storageに画像をアップロードして、サムネイルをCloud Functionsで生成しているケースは多いと思います。
公式のサンプルでもCloud StorageのonFinalizeをトリガーにして、サムネイルを生成していますよね。
ただし、途中からサムネイルを生成するようになった、サムネイルのサイズを増やしたいなどのパターンでは、新規のクラウドファンクションを作成しても、すでにアップロードされた画像はonFinalizeのトリガーが発生せずに、サムネイルが生成されません。
そのため、他の方法を考える必要があります。
前提条件
今回この記事で参考になりそうな方はこのような条件です。
- Cloud FunctionsのonFinalizeトリガーでサムネイルを生成している。
- すでにアップロード済みの画像に対してサムネイル生成したい。
- 簡単な実装でonFinalizeトリガーを発生させたい。
- node.jsでスクリプトを書いて全ファイルに対して一括処理させたい。
ファイルをローカルにダウンロードしてアップロードしなおす(没案)
没案なので、読み飛ばしてもらって構いません。
当初は、画像をローカルの一時フォルダに格納し、それを同じ場所にアップロードし直せばonFinalizeトリガーが発生するので良いのではと考えていました。
没案となった実装内容
アップロード処理に関してはコミット履歴に残っていなかったのでTODOコメントとしました。
1行でかける処理だと思います。
// Storageから取得した画像パスに対する処理
imagePaths.forEach((imagePath) => {
// 一時ディレクトリにdownloadディレクトリを作成する
const downloadPath = os.tmpdir() + '/download/'
// downloadディレクトリにStorageから取得した画像のパスを結合して、ローカル上の一時的なファイルパスとする
const tempFilePath = downloadPath + imagePath;
// storageから画像をローカルに保存する
await bucket.file(imagePath).download({destination: tempFilePath});
// TODO: アップロード処理
}
もちろんこれでも実現できますし、そんなに実装量も気にするほどではありませんが、デメリットも考えられます。
デメリット
- 自分のPCのローカルストレージに一時的にファイルを置くため、ストレージ容量が足りないなどの問題が発生する可能性がある。
- ダウンロードしてアップロードしなおす時のファイルパスが完全に一致するか検証しなければならない。
そして何よりもっとシンプルに書く方法はないかと辿り着いた結果が採用案になります。
オブジェクト名を変更する(採用案)
Cloud StorageのonFinalizeトリガーについて
Cloud StorageのonFinalizeトリガーは、バケットで新しいオブジェクト(または既存オブジェクトの新しい世代)が正常に作成された場合に送信されます。既存のオブジェクトのコピーまたは書き換えを行った場合にも送信されます。アップロードが失敗した場合、このイベントはトリガーされません。
既存のオブジェクトの名前を変更
「既存のオブジェクトのコピーまたは書き換えを行った場合」がポイントです。
オブジェクト名の変更を行うことでonFinalizeトリガーが動くのではないかという予想が立ちました。
ただし、オブジェクト名は変更しますが、違う名前に書き換えてしまうと参照先のパスも変わってしまうので同じ名称に変更しなければなりません。
同じ名称にしたときに、オブジェクト名の変更として扱ってくれるかというのはポイントでしたが、問題ありませんでした。
オブジェクトの名前変更、コピー、移動についての公式ドキュメントはこちら
採用した実装内容
imagePaths.forEach((imagePath) => {
await file.move(imagePath);
}
はい、すごくシンプルな実装にすることができました。
画像パスの面倒な結合処理などもなくなりましたし、ダウンロード => アップロードといった手順を踏まず、ファイルに対してmoveとすれば良いだけです。
ローカルのストレージを使用することもないので、容量を気にする必要もありません。
こちらを実行するとオブジェクト名の変更が行われ、onFinalizeが呼び出されました。
それによってアップロード済みの画像のサムネイルも生成することができました。
最後に
これに辿り着けたのは弊社内でペアプロを実施したのが大きかったです。
もともと前任の方のソースコードを引き継いでいて、アップロードからダウンロード処理するものだと思い込んでいたんですが、すごくシンプルな案にまとめることができました。