Google Cloud Storage に Write したときは Close の戻り値を必ず確認する
Go言語で Google Cloud Storage を扱う cloud.google.com/go/storage という公式のパッケージがあります。
GCS にファイルをアップロードする処理で、io.Writer のインタフェースを経由してデータをアップロードすることになります。
Writer の取得までは以下のようなコード:
client, err := storage.NewClient(ctx)
if err != nil {
return err
}
bkt := client.Bucket("bucketname")
obj := bkt.Object("filename1")
w := obj.NewWriter(ctx)
そして Write するときに、いつもの癖で以下のように書くと……ダメです:
...
w := obj.NewWriter(ctx)
defer w.Close()
_, err := w.Write([]byte("こんにちは!こんにちは!"))
if err != nil {
return err
}
// アップロード成功!……とは限らない
ドキュメントを読んでみましょう。
Write appends to w. It implements the io.Writer interface.
Since writes happen asynchronously, Write may return a nil error even though the write failed (or will fail). Always use the error returned from Writer.Close to determine if the upload was successful.
下の段をGoogle翻訳:
書き込みは非同期的に行われるため、書き込みが失敗した(または失敗する)にもかかわらず、書き込みがnilエラーを返すことがあります。常にアップロードが成功したかどうかを判断するには、Writer.Closeから返されたエラーを使用します。
この通り Close の戻り値を確認する必要があります。書き込みが非同期なのがポイントで、Writer は内部では io.PipeWriter に Write しているだけです。この Pipe に送られたデータは非同期で GCS に送信されます。通信でエラーが発生しても、Write は成功する場合があるのです(というよりは Write はほぼ成功します、オンメモリの操作なので)。
正しくは以下のように Close の戻り値を確認します:
client, err := storage.NewClient(ctx)
if err != nil {
return err
}
bkt := client.Bucket("bucketname")
obj := bkt.Object("filename1")
w := obj.NewWriter(ctx)
_, err := w.Write([]byte("こんにちは!こんにちは!"))
if err != nil {
w.Close() // これは要るかどうか?
return err
}
// このチェックを忘れずに!
if err := w.Close(); err != nil {
return err
}
// ここまで来たらアップロード成功!
この記事はQiitaの記事をエクスポートしたものです
Discussion