reload した後 h2oの古いプロセスが残り続ける場合
h2o は graceful restart をするのだが、稀に古いプロセスがずっと残ることがあって困ってた。(正確には start_server が restart させていて、h2o 自体は graceful shutdown しているだけ)
一例としてはこういう感じ (これは単に SIGHUP 直後なだけだけど、ときどき reload するとプロセスが残っていく)
$ sudo systemctl status h2o
● h2o.service - H2O HTTP Server
Loaded: loaded (/etc/systemd/system/h2o.service; enabled; preset: enabled)
Active: active (running) since Sat 2026-01-10 17:36:22 JST; 2 weeks 4 days ago
Process: 902234 ExecReload=/bin/kill -s HUP $MAINPID (code=exited, status=0/SUCCESS)
Main PID: 1288 (perl)
Tasks: 23 (limit: 2274)
Memory: 53.0M (peak: 1015.0M swap: 12.2M swap peak: 95.1M)
CPU: 1h 38min 58.048s
CGroup: /system.slice/h2o.service
├─ 1288 perl -x /usr/local/share/h2o/start_server --pid-file=/var/run/h2o.pid --port=0.0.0.0:80 "--port=[::]:80" --port=0.0.0.0:u443 "--port=[::]:u443" --port=0.0.0.0:443 "--port=[::]:443" -- /usr/local/bin/h2o -c /srv/www/h2o.conf.yaml
├─897714 /usr/local/bin/h2o -c /srv/www/h2o.conf.yaml
├─897716 neverbleed
├─897735 perl -x /usr/local/share/h2o/annotate-backtrace-symbols
├─902237 /usr/local/bin/h2o -c /srv/www/h2o.conf.yaml
├─902238 neverbleed
└─902257 perl -x /usr/local/share/h2o/annotate-backtrace-symbols結論: http*-graceful-shutdown-timeout を設定しよう
まず以下のような設定をし忘れないように。この例だと30��で強制切断。デフォルトが0(無効)
http2-graceful-shutdown-timeout: 30 http3-graceful-shutdown-timeout: 30
メモ: タイムアウトの仕組み
HTTP/2 (lib/http2/connection):
- initiate_graceful_shutdown → 最初のGOAWAY送信
- 1000ms後 → graceful_shutdown_resend_goaway → 2回目のGOAWAY送信
- もし http2-graceful-shutdown-timeout > 0なら、その時間後に強制終了
HTTP/3 (lib/http3/server.c):
- 同様に1000ms後に2回目のGOAWAY
- もし http3-graceful-shutdown-timeout > 0なら、その時間後に強制終了
HTTP/1 (lib/http1.c):
- Keep-Alive をオフにしてレスポンス終了時 close
とにかくタイムアウトは全部設定しておこう!
調査
ただこの2つを設定していても接続が残るケースが発生して悩んだ
$ sudo ss -tapn | grep 902501
ESTAB 0 0 127.0.0.1:54080 127.0.0.1:5001 users:(("h2o",pid=902501,fd=66))
ESTAB 0 0 127.0.0.1:46754 127.0.0.1:3000 users:(("h2o",pid=902501,fd=72))
CLOSE-WAIT 1 0 127.0.0.1:52768 127.0.0.1:80 users:(("h2o",pid=902501,fd=74)) CLOSE-WAIT が残っている。
→ 最終的にこれは grafana の websocket への接続がずっと残っているというものだった。ブラウザの grafana タブを閉じたらプロセスが消えた。なんで CLOSE-WAIT?
websocket の proxy.timeout.io はデフォルト30秒らしいけど、通信が続くと一生切断されないのかも?
関連エントリー
- h2o を systemd 管理下にした 徐々に daemontools 依存を外していってるが、とりあえず h2o を systemd に管理にすることにした。どうも daemon...
- Ubuntu 20 から 24 に do-release-upgrade LLM にリリースノートと ps aux の結果とかを食わせながら注意点を適当にあらいだしてやった。こういうときペアでやってる感じがあってだ...
- prometheus + grafana のセットアップ (Ubuntu 16.04.4 LTS) メトリクスの可視化をもうちょっとやりたくて prometheus と grafana をセットアップした。監視は mackerel でやって...
- Raspberry Pi から HDMI-CEC コントロール サイネージ HDMI CEC 連携 カレンダーを表示するおうちサイネージ というのを作っていたがモニタの置き場がなくなってしまったので、テレ...
- LAN 内の mDNS に応答するホストを列挙したい PTR _services._dns-sd._udp.local. A/AAAA [ソースアドレス].in-addr.arpa. をやりたい...





