on
S3 にファイルをマルチパートアップロードする CLI ツールを作った
TweetS3 にファイルをマルチパートアップロードする CLI ツールを作った
作ったものはGitHubに上がっています。 s3go という S3 にファイルをマルチパートアップロードしてくれる CLI ツールを作成しました。 現状、AWS の SDK(aws-sdk-go)はマルチパートアップロードの API をサポートしていません。そのため、aws-sdk-go を使わずに一から AWS の API を利用するコードを書きました。
今回、CLI ツールを作ったのは、goroutine の学習のためです。 goroutine については書籍等読んで学習していましたが、せっかくなので実際に使いたいなと思ったのがきっかけです。 マルチパートアップロードならアップロードの処理を並列に実行できるなと思い、今回の CLI ツールを作成しました。 実施に今回の CLI ツールでは goroutine を使ってアップロードの処理を並列化しています。
マルチパートアップロードとは
ざっくりいうと、マルチパートアップロードとはファイルを小さい単位に分割し、分割されたファイルをアップロードし、それをサーバー側で結合して、1つのファイルのアップロードを行うというものです。
難しかったらところ
やはり goroutine のコードをは難しかったです。 今回はアップロードの処理を goroutine を使って並列化しました。 並列化した部分のコードは以下です。
func (s \*S3Upload) PutObject() error {
var wg sync.WaitGroup
errChan := make(chan error)
done := make(chan interface{})
var errors error
go func() {
for err := range errChan {
if err != nil {
errors = multierror.Append(errors, err)
}
}
defer close(done)
}()
for n := range s.fileSlice {
wg.Add(1)
go func(n int) {
s.PutMultiPartObject(n+1, errChan)
defer wg.Done()
}(n)
}
wg.Wait()
close(errChan)
<-done
return errors
}
今回は sync.WaitGroup を利用して goroutine の制御を行いました。
sync.WaitGroup は wg.Add(1)をすると内部変数がインクリメントされ、wg.Done()を実行するとデクリメントされます。
wg.Wait()は内部変数が 0 になるまで処理を待ちます。
goroutine で関数を実行し、goroutine で実行した関数が終了するときにdefar
でwg.Done()
を呼び出します。
sync.WaitGroup の Wait メソッドを利用することで、goroutine が全て終了したことを確認し、安全に関数を終了できます。
gorutine で実行している関数には err チャネルと引数で渡します。 err チャネルには関数内で起きたエラーが送信されてきます。 err チャネルからエラーを読みとる関数を goroutine で実行します。 goroutine で読み取らないと error をチャネルに書き込めずにデッドロックを起こします。 err チャネル経由できた error は hashicoro/go-multierrorr を使って一つの error にまとめます。
まとめ
定期的に何かを作って今後もブログ書きたいと思います。