Server::Starterを利用すれば、hot-deployが実現出来る。
- perl実装
- go実装
Server::Starter とは
start_server
をざっくりと説明すると、 start_server
が作成したsocketを子プロセスへ共有して、あとは start_server
にSIGHUPのシグナルを送ってあげることで、子プロセスを入れ替えてhot deployが出来るものだ。詳しくは以下の記事を読んでも良いし、実装自体も少ないのでコードを読めば良い。
Server::Starterから学ぶhot deployの仕組み - $shibayu36->blog;
この子プロセスというのは、start_server
の子プロセスになるだけで、以下のような特定の条件を満たせればなんでも良いのだ。
- hot deploy時に
start_server
がSIGTERMを子プロセスへ送るので、SIGTERMによりgraceful shutdownを行う - 子プロセス起動時に
start_server
が作成したファイルディスクリプタの情報が環境変数で渡ってくるので、それを用いてacceptする (しなくてもいい)
この対応は、過去にも多くの人がやってきたことではあるが、Rustでも簡単に出来るように、今回、子プロセス用のcrateを作成した。
https://crates.io/crates/server-starter-listener
SERVER_STARTER_PORT と TcpListener / UnixListener
通常tcp接続のためのTcpListenerやunix domain socketのためのUnixListenerは、以下のようにbindをして利用する。
TcpListener::bind("localhost:8080") UnixListener::bind("/path/to/socket")
しかし、 start_server
を利用する場合は、親プロセスで作成されたファイルディスクリプタを流用する必要がある。start_server
では SERVER_STARTER_PORT
という環境変数から情報が渡ってくるため、こちらからファイルディスクリプタを取得する。ファイルディスクリプタを流用するインターフェースはRustにはきちんと備わっており、明示的に以下のようにFromRawFdをuseすると利用することが出来る。
use std::os::unix::io::FromRawFd; let tcp_listener = unsafe { TcpListener.from_raw_fd(fd) }; let uds_listener = unsafe { UnixListener::from_raw_fd(fd) };
server-starter-listener-rs では、このlistenerを取得する部分までを行ってくれる実装になっている。
actix-web
Rustでよく使われるWebFrameworkの一つがactix-webである。actix-webではTcpListenerを受け取るAPIが用意されているためserver-starter-listener-rsから受け取ったlistenerをそのまま渡してあげれば良い。
let listener = server_starter_listener::listeners()?.pop()?; HttpServer::new(|| { App::new() .wrap(middleware::Logger::default()) .service(web::resource("/hello").route(web::get().to(|| HttpResponse::Ok()))) }).listen(listener)?.run()?
また、 unix domain socketを利用する listen_uds
も用意されており、こちらは以下のようにfeatureを有効にすると利用出来る。
[dependencies] actix-web = { version = "...", features = ["uds"] }
最初に書いたように子プロセスへはSIGTERMを送った際にgraceful shutdownする必要があるのだが、以下にある通り、actix-webではgraceful shutdownが出来るようになっている。
actix-website/server.md at e5fb02d5af86d0abe505a0bf6684362f368c333f · actix/actix-website · GitHub
以上から、Rust (主にactix-web) ではServer::Starterを使えば、気軽にhot deploy出来ることが分かる。
こちらで利用したサンプルコードは、以下のrepositoryのexamplesにもある。
最後に
こちらの記事は FOLIO Advent Calender 2019 として書かれた。
今の所、社内にRustのコードは1つも無いが、社内Slackに #lang-rust channelはある。