タイムアウト(キャンセル)を context.Context に寄せてみる

気が向いたので前書いた go のライブラリの一つのタイムアウトの指定(キャンセルも含む)を context.Context に寄せてみた。 (https://github.com/soh335/test-mysqld-docker/pull/6) このライブラリは docker で test 用の mysqld のプロセスを管理するもの。

NewMysqld() を呼ぶとタイムアウトするまで docker で mysql を立てて、ピングが通ったら dsn を知ることができるという流れになっている。

今までは config struct に timeout の指定を入れて渡していた。こんな感じ。( nil だった時はこの config の値をデフォルトで指定してたけど)

config := &MysqldConfig{ Tag: "mysql:latest", Timeout: 30 }
mysqld, err := mysqltest.NewMysqld(config)
if err != nil {
    log.Fatal(err.Error())
}
defer mysqld.Stop()
db, err := sql.Open("mysql", mysqld.DSN())
...

それを context に寄せて見たものがこれ。

ctx, cancel := context.WithTimeout(context.Background(), time.Second*30)
defer cancel()
mysqld, err := mysqltest.NewMysqld(ctx, "mysql:latest")
if err != nil {
    log.Fatal(err.Error())
}
defer mysqld.Stop()
db, err := sql.Open("mysql", mysqld.DSN())
...

config の内容が tag しかなくなってしまったので、string として渡すようにした。

個人的には defer を二つ書かないといけないのがちょっと見栄えが良くないな…と感じた。ドキュメントとか関数名次第であると思うけど、直感的に cancel がここでいう NewMysqld だけに効くのか Stop にも効くのか分かりづらいなぁという感じ。大抵 context を渡すのって何かの操作一つだからかな。 そういう意味では、NewMysqld より Start とかの方が context が効く範囲がわかりやすいかも?

まぁ内部だけで使うにしても、標準ライブラリも context に色々対応してきたし使った方が楽なことが多いので、使っていきたいとこ。