Ros
短命プロセスの後始末は cgroup に任せる (systemd-run --scope)
ros2 run/launch の子は親の terminate で死なず残留・混信する。setsid+killpg の手書きは手続き依存で失敗する。systemd-run --user --scope + RuntimeMaxSec なら掃除を忘れても cgroup ごと必ず死ぬ
要点: 短命の検証プロセス (ROS プローブ等) は systemd-run --user --scope --collect -p RuntimeMaxSec=N -- <cmd> で起動する。プロセスツリーが cgroup で丸ごと管理され、掃除の手続きを忘れても時間で必ず全滅する。
問題
ros2 run/ros2 launchはラッパーで、親への SIGTERM が実行体まで届かないことがある- 生き残りノードは DDS が自動発見するので、次の検証と混信する (「設定を変えたのに挙動が変わらない」の典型原因)
- launch は悪質: セッションリーダーだけ死んで子ノード多数が孤児化した実例あり (残った teleop が数時間後に機体を動かした)
従来の対処と欠点
| 手法 | 欠点 |
|---|---|
proc.terminate() | 子が残る |
setsid + killpg | killpg を忘れる・書き間違えると孤児。毎回の手書きが必要 |
pkill -f <pattern> | パターンが自分のシェルのコマンド文字列に一致して自爆 (exit 144) |
timeout N setsid ... | SIGTERM がセッションリーダーにしか届かないケースあり |
共通の弱点: 手続きに依存していて、1 回忘れると事故る。
解決: systemd-run --user --scope
systemd-run --user --scope --collect --quiet -p RuntimeMaxSec=5 -- \
ros2 topic echo /joint_states --once- scope = cgroup。fork した孫プロセスも全部同じ cgroup に属す
RuntimeMaxSec経過で cgroup ごと SIGTERM → SIGKILL。構造で殺すので取り漏らしが原理的に無い--collectで失敗 unit も残らない- フォアグラウンドでブロックするので、呼び出し側の timeout / Ctrl-C とも整合
- daemon 権限不要 (
--user)
実測: bash -c 'sleep 30 & sleep 30 & wait' も ros2 topic pub -r 5 も、時間経過後の残存プロセスゼロ。
ラッパー例
#!/bin/bash
# rosprobe <max_seconds> <command...>
set -euo pipefail
MAX="$1"; shift
exec systemd-run --user --scope --collect --quiet -p "RuntimeMaxSec=${MAX}" -- "$@"併用すべき分離策 (混信の構造的防止)
- 検証は
ROS_DOMAIN_IDを稼働スタックと分ける (同名ノード二重化で購読先が不定になる) - プローブ用トピック名は毎回変える (/probe3/... 等)
関連
- [[agent-ros2-debug-loop]] — エージェントが短命プローブを多用する構成。この掃除法が前提
最終更新: