update.6月からDMM.comラボの六本木オフィスでミドルウェアを作るエンジニアインターンをしている@kawasin73です。DMM.comラボではluaで実装されたKVS(キーバリューストア)を利用しています。するKVSで、社内でluaの皮を被ったC言語で実装されたものが運用されています。ラボの方が行い、実装は僕がすることになりました。channel等)については僕が学びながらそれについて都度相談するというスタイルで行なっています。その開発記を連載しています。Shutdownを実装していきます。はじめに開発環境は以下の通りです。Gogland今回開発した内容は、こちらのリポジトリのtcp5ディレクトリで公開しています。ShutdownとはShutdownは、処理中のリクエストがあったとしても完了を待たずに即座にサーバーの終了を行います。そのため、クライアント側ではリクエストが正しく処理されたかどうかはわからなくなります。Shutdownでは、新しいリクエストの受付を停止し、処理中の全てのリクエストの完了後にサーバーの終了を行います。Shutdownの処理も実装しました。再起動Listenするホスト名やログファイルのパスなどを外部ファイルや環境変数などで設定している時、再起動ができるようになると変更をゼロダウンタイムで反映することができるようになります。再起動には2種類の手順があります。Listenするホスト名とポート番号が変わらない場合Listenするホスト名とポート番号が変わる場合です。Listenするホスト名とポート番号が変わらない場合、ListenerをCloseする必要はありません。Configを再設定するだけで再起動の処理は終わります。Listenするホスト名とポート番号が変わる場合は、Listenerを切り替える必要があります。Shutdownこのようにホスト名とポート番号が変わるか変わらないかで処理を変更することで設定値の変更をゼロダウンタイムで行うことができます。機能追加やバグの修正などでサーバーの処理を変更して新しいバイナリに変更する場合の再起動は、別の仕組みで対応する必要があります。バイナリの変更を伴う再起動はこの章では扱いません。Shutdownの処理を追加します。5050fe3e49fa29c22404e8b525e4fce34438d732処理としては、Shutdownの時と同じ処理です。次にConnの処理を追加します。シグナルを受け取った時にReadを終了し、すでにReadしているもののWriteが全て終了するのを待って、コネクションを終了します。Writeはgoroutineで非同期化されているので、どこまでWriteが終了しているかを知る必要があります。それには、sync.WaitGroupを使います。ShutdownがされたらhandleConnectionの中でc.conn.CloseRead()c.wg.Wait()をします。これ以降のReadを終了し、Writeが全て終わるまで待ちます。実装する続いて再起動を実装します。Shutdownします。Serverを再利用したいですがctxGracefulは一度しか使えません。Shutdownを実現することにしました。context.CancelFunc}そして、Connに*Serverと*contextsを持つようにします。Shutdownします。Shutdownさせます。contextsが変更されたことを、handleListener()のgoroutineに通知するために、バッファーサイズが1のchannelを利用しました。}これによって、もしcontextsが変わっていたら更新して、変わっていない場合は以前のcontextsを使うという処理ができます。}}syscall.SIGHUPを受け取った時に再起動します。再起動を実現するためにはループを使うので、for文を使います。再起動の時は、continueをして処理を継続します。サーバーエラーの場合は、returnをしてループから抜けています。stringでホスト名をロードするようにしていますが、ホスト名のローディングに細工をしています。それにより、再起動をすると以下のような挙動になります。立ち上げた時は127.0.0.1:12345をListenします。一度再起動すると、127.0.0.1:12346にポート番号を変更します。2回目以降は、再起動してもホスト名とポート番号は変更しません。Shutdownと再起動の実装が完了しました。ここからは正しく動いているかを確かめていきます。ShutdownとShutdownの違いを見分けることが難しいです。そのため、以下のようにWriteをするまでに5秒スリープさせてReadしてからWriteするまでを遅延させます。送信macOSでは、以下のようにしてアクティビティモニタからGUIでシグナルを送信することができます。サーバーのプロセスを選択し、アクティビティモニタのステータスバーにある「表示」->「シグナルをプロセスに送信」を選びます。main.goでサーバーを立ち上げた場合は、mainというプロセス名になっています。送るシグナルの種類を選択して、「送信」ボタンを押します。これで自由にシグナルを送ることができます。以下のコマンドでechoサーバーが立ち上がります。12345とすると、接続できます。何か文字列を打ち込んで送信し(Enter)同じ文字列が5秒後にレスポンスされることを確認しましょう。複数のリクエストをレスポンスを待たずに送信し、すぐにアクティビティモニターでシグナルを送ってみてください。SIGTERMでは、シグナルを送った時点でtelnetの接続が切断されサーバーが終了します。SIGQUITでは、全てのレスポンスが返ってきた後に接続が切断されます。SIGQUITを送った後に送信したリクエストは無視されています。Shutdownのように切断されます。一度telnetで127.0.0.1:12346に接続すると再接続することができます。SIGHUPを送ると接続が切断されますが、また127.0.0.1:12346に接続することができます。Shutdownと再起動可能なTCPのechoサーバーの実装は完了です。Kawa@kawasin73ソフトウェアエンジニアです。東京大学4年Go/Ruby/Swift/Python/Javascript/Java/Chttps://kawasin73.hatenablog.com/FollowDMM.com総合エンタテイメントサイト「DMM.com」を運営。会員数は2,900万人を突破。動画配信、FX、英会話、ゲーム、太陽光発電、3Dプリンタなど40以上のサービスを展開。沖縄での水族館事業参入、ベルギーでのサッカークラブ経営など、様々な事業を手掛ける。VENTURES」による出資や、M&Aなどを積極的に展開している。upLoginユーザーは見つかりませんでした。