AWS-SDK-Goを使って、ユーザーが投稿したファイルをS3から削除してみる

はじめに

S3でユーザーが投稿した画像を管理している場合、ユーザーがアプリを退会した際にユーザーに関する情報、S3からもユーザーのファイルを削除する必要性があります。

S3上のプレフィックスは userID/ となっており、全体のキーはbucket/userID/fileName.jpg となっています。

 

問題点

AWSの制約上、bucket/userID以下にファイルが1つでもあると、
いきなりbucket/userIDを削除することはできません。

加えて、リストを取得するListObjectsでは1度に1000個のキーか取得することができず、
オブジェクトの削除を行うDeleteObjectも1度に1000個のキーまでしか指定できません。

もしユーザーが1000個以上のファイルをアップロードしている場合、
一筋縄ではいかないため工夫する必要性があります。

 

コード

 

解説

ユーザーが投稿したファイルを全て取得する

最初のリクエストをする際に、Delimiter: aws.String(userID + "/"),をつけてリクエストをすることで、レスポンスにIsTruncatedが含まれています。

IsTruncatedtrueだと全てを取得できず、まだ残りのオブジェクトがある状態
falseだと全てのオブジェクトを取得できた意味をします

 

最初のリクエストでIsTruncatedtrueの場合、
NextMarkerがレスポンスに含まれているのでこれを次のリクエストに含めておきます。

ループの中でこれらを繰り返しておき、
IsTruncatedfalseになった時点で終了。この関数では[]stringを返します。

 

オブジェクトを削除する

関数全体↑

 

getAllObjectで取得したキーが入った配列の長さが1000以上だった場合、
先程述べた様に、1度のリクエストで削除できるキーが最大1000のため配列を分割する必要性があります。

 

func chunk()では1000要素以上の配列に入ったキーから1つの配列が1000個未満のキーとなるように複数の配列に分割して[][]stringを返します。

 

この分割された[][]stringfor-rangeでループさせ、画像を削除していきます。

 

bucket/userID 以下のファイルが0になったら、bucket/userIDを削除します

 

使い方

ちなみに画像数が5,000枚レベルになると、マシンのスペックにもよりますがAPIサーバーからアプリへレスポンスを返すまでに1分程度、かかってしまいとても使えたものではありません。

なので、今回はDBからユーザーの情報を削除する部分はGoroutineで制御し、
このS3から画像を削除する部分はレスポンスを返した後に実行されるようにしてみました。

DBからユーザー情報を削除する部分はerrgroup(goroutine)で制御を行って、
エラー処理ができるように。全ての処理が終わったあとに、

 

WaitGroupをインクリメントしておき、wg.Wait()をせずにそのままreturn nilでレスポンスを返します。
ただ、これを行うとS3から画像を削除する部分でエラーを起こるとユーザーへ通知できなくなってしまうので、Slackへ通知するようにしてます。
(そして手作業で該当ユーザーのファイルを削除していく…)

 

おわり

Go言語に自信が全く無い素人のコードを晒して大変恐縮していますが
もし間違いや、こうした方がいいのご指摘がありましたらぜひコメントしていただけると本当に幸いです。

コメントを残す

メールアドレスが公開されることはありません。