なんかごく一部に補足されているので、念のため軽く説明しておきます。


これ、ベストな方法だとは思っていないんだけど、最初にこれを書いた当時の考え方は以下の通り:

  1. これは自分の部署で初めて 本番に設置するgoアプリである
  2. 一次対応をする人は自分とは限らない
  3. 細かいコード内容の修正はともかく、明らかなバグっぽいものの修正(例:SQL文の変更)などを自分以外の人間が施した後にサーバーを簡単に再コンパイル+再起動するする方法がないと椅子が降ってくる事が容易に予想される
というところから、どうするのがベストか考えたのがきっかけ。以下、やった事の詳細。

まず、何が起こっているのか見るのにApacheログ的なものとエラーログが必要であろう。今回フレームワークは使っておらずgoのnet/httpを生で使っていた。エラーログはとりあえずlog.PrintfでいいとしてApacheログ的なものは必要・・・と思ったがそれらしきものがぱっと出てこなかったので、Perl5のApache::LogFormat::Compilergoに移植して、それを使うようにした。これでリクエストが来てるURL等が判断できる。

ログを吐き出す機能を書いた瞬間に経験値から得られる特殊能力により「はっ!ログをローテートしないとマサカリが飛んでくる!」と思い、次にPerl5のFile::RotateLogsと同等の機能が必要だ!と思い、それをgoに移植して、使うようにした。ちなみにこの機能を書いた事によってgoでファイルディスクリプタをリークさせるとどうなるか、という貴重な経験値を得る事ができた。こけない方法を学んだ

デーモン本体は古き良きdaemontoolsで起動の管理をしている。そこはあえて変える必要もないのでそれはいいとして、他のほぼ全てのサービスではHUPとTERMを使ってプロセスの管理をしているから、それに準じた方がわかりやすくなるはず、ということで同じ手法を取るにはどうするか考えた。ここはやはりあちこちで使ってるServer::Starterを使うのが一番他の人にも簡単だろう、と結論。

でもServer::Starterに対応するためにはポートにバインドする側でそれに対応しなくちゃいけなくて・・・あとついでにgraceful shutdownもやりたいから・・・と色々ぐぐったりしてたら、とりあえずmannersなるライブラリでnet/httpで提供されるサーバーに対してはgraceful shutdownは提供されることがわかった。だが当然Server::Starter対応はない。しょうがない。ということでServer::Starterへの対応を可能にするコードをgoで書いた

ここではたと気づくわけです:「ん、start_serverをかませることができるということは、前のプロセスを残したまま次のプロセスの起動をまてるから・・・opsの人が変更を入れて再起動もしようと思えばできるわけだな」と。だけど、go buildとかgo installとかそういうのを覚えるのきっといやでしょう。俺もいやだもん。

そこでdaemontoolsから呼び出されるコマンドはシェルスクリプトのラッパーにした。

daemontools側のrunファイルはこんな感じ:
#!/bin/sh
start_server --port 8080 -- /path/to/myproject/bin/server.sh
で、server.sh側はこんな感じ:
#!/bin/sh
if [ ! -e "/path/to/myproject/go/bin/server-binary" ]; then
# GOPATHとか色々あるけどここでは割愛
go get ...
go build -o /path/to/myproject/go/bin/server-binary ...
fi
exec /path/to/myproject/go/bin/server-binary

という感じで、goのバイナリファイルがあるかどうかだけ確認する。なかったらビルドする。ビルド失敗したらそれまでだけど、start_serverが前の世代を持っててくれるからとりあえずサービスは止まらない。これにより、自分以外のgoの事をよく知らない人がちょっとソースコードを修正して緊急再起動しようとした場合においても、さすがにシェルスクリプトで ! -e が何をしているのかはわかるはずなので、とりあえず作業はできる。実際SQLの微調整とかはそれでやってもらった事もあります。

バイナリは本当は前もってコンパイルしておいてそれを配布がいいのだろうけど、まぁそういう微調整もあるだろうし、ということで今は各マシンでコンパイルできるようにしてる。

と、まぁ以上ベストプラクティスだとは思ってないけど、goで徒手空拳の状態から自分以外の、特に椅子やマサカリを投げ込んできそうなopsの人が そのソースコードに手を入れるはず、という前提を持って作った仕組みが以上でした。強くおすすめはしないけど、色々条件が合うようなら悪くない仕組みだとは思います。YMMV