delete

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個以上のファイルをアップロードしている場合、 一筋縄ではいかないため工夫する必要性があります。   コード   解説 ユーザーが投稿したファイルを全て取得する [crayon-5b4efab0daf12482787909/] 最初のリクエストをする際に、Delimiter: aws.String(userID + "/"),をつけてリクエストをすることで、レスポンスにIsTruncatedが含まれています。 IsTruncatedがtrueだと全てを取得できず、まだ残りのオブジェクトがある状態 falseだと全てのオブジェクトを取得できた意味をします   [crayon-5b4efab0daf20301505137/] 最初のリクエストでIsTruncatedがtrueの場合、 NextMarkerがレスポンスに含まれているのでこれを次のリクエストに含めておきます。 ループの中でこれらを繰り返しておき、 IsTruncatedがfalseになった時点で終了。この関数では[]stringを返します。   オブジェクトを削除する [crayon-5b4efab0daf2a327306886/] 関数全体↑   [crayon-5b4efab0daf2d931869920/] getAllObjectで取得したキーが入った配列の長さが1000以上だった場合、 先程述べた様に、1度のリクエストで削除できるキーが最大1000のため配列を分割する必要性があります。   [crayon-5b4efab0daf30926252724/] func chunk()では1000要素以上の配列に入ったキーから1つの配列が1000個未満のキーとなるように複数の配列に分割して[][]stringを返します。   [crayon-5b4efab0daf33021395263/] この分割された[][]stringをfor-rangeでループさせ、画像を削除していきます。   [crayon-5b4efab0daf3d204231538/] bucket/userID 以下のファイルが0になったら、bucket/userIDを削除します   使い方 ちなみに画像数が5,000枚レベルになると、マシンのスペックにもよりますがAPIサーバーからアプリへレスポンスを返すまでに1分程度、かかってしまいとても使えたものではありません。 なので、今回はDBからユーザーの情報を削除する部分はGoroutineで制御し、 このS3から画像を削除する部分はレスポンスを返した後に実行されるようにしてみました。 [crayon-5b4efab0daf40288408502/] DBからユーザー情報を削除する部分はerrgroup(goroutine)で制御を行って、 エラー処理ができるように。全ての処理が終わったあとに、   [crayon-5b4efab0daf43581143495/] WaitGroupをインクリメントしておき、wg.Wait()をせずにそのままreturn nilでレスポンスを返します。 ただ、これを行うとS3から画像を削除する部分でエラーを起こるとユーザーへ通知できなくなってしまうので、Slackへ通知するようにしてます。 (そして手作業で該当ユーザーのファイルを削除していく…)   おわり Go言語に自信が全く無い素人のコードを晒して大変恐縮していますが もし間違いや、こうした方がいいのご指摘がありましたらぜひコメントしていただけると本当に幸いです。

Node.jsのプログラムをsystemdで動かすと意図しない動作をどうにかする

背景 Node.jsで書かれたプログラムをsystemdで動かすと 実行ディレクトリが変わってソースによっては意図しない動作をします。 例 コード [crayon-5b4efab0db3ba912185076/] 例 systemd Unitファイル [crayon-5b4efab0db3c5877220238/] 例 結果 [crayon-5b4efab0db3c8991324819/] requireで読み込んだプログラムはキャッシュされるため 逐一、使用する場面でキャッシュを削除し再度読み込むようなプログラムです。 systemd で動かすと結果の通り、キャッシュを削除していても Unix タイムスタンプが変更されずにいます。   原因 ソースコード fs.writeFileSync('/tmp/blog-test.log', path.resolve('date.js')); node test.js /root/blog-test/date.js systemd /date.js path.resolve('date.js')は相対パスから絶対パスを取得する部分ですが これがうまく動いていません。 systemd は cgroups を使って管理されるため プログラムの実行パスが / となり、delete require.cache が動きませんでした。     解決方法 サーバー上では systemd で起動しています。 各エンジニアのローカル環境でも正常に動いてほしいので サーバー上に環境変数を用意して雑に対応しました。 [crayon-5b4efab0db3ca370901153/]     思ったこと 「○○エンジニアは、○○だけに精通していれば良い」という人に反対です