Muninプラグインをshellスクリプト等で自作する中で、スクリプト内でバックグラウンド実行したいときは書き方に注意が必要だ。
例えば、スクリプト内で集計をして集計結果を出力したいとする。集計に時間がかかるので集計結果をファイルに吐いておき、出力は出力済みのファイルを読むだけにする。集計処理はバックグラウンド実行になる。

スクリプトを以下のように作成する。

/usr/share/munin/plugins/originalplugin_

#!/bin/sh

target=`echo $0 | awk -F_ '{print $2}'`

略

val1=awk '{print $1}' /tmp/${target}_result.txt
val2=awk '{print $2}' /tmp/${target}_result.txt
echo "val1.value ${val1}"
echo "val2.value ${val2}"

# 集計する。最後に${target}_resultに出力される。

calculate_command $target &

pluginsディレクトリにsymlinkを貼る。

ln -s /usr/share/munin/plugins/originalplugin_ /etc/munin/plugins/orignal_targetname1

Munin Nodeサーバ上でmunin-run original_targetname1を実行すると、集計部分はバックグラウンド実行され、すぐに結果が出力される。
しかしMuninのMasterサーバから実行されたときは、集計が終わるまで結果が返ってこない。もし集計がMuninのtimeout値を超えるようであれば、エラーとなり、/var/log/munin-node/munin-node.logにService 'orignal_targetname1' timed out.と出力されてしまう。

MuninのMasterから実行されるときは、Munin NodeへTCP通信をして、fetch plugin名と命令を出す。
上記のスクリプトではバックグラウンド実行されていてもコマンド終了時まで標準出力を保持してしまい、TCP通信が閉じられない。
理屈としてはSSHでコマンド実行した時にコマンド終了後も制御が戻らない時の対処方法と似ている。

対策はSSHでコマンド実行した時にコマンド終了後も制御が戻らない時の対処方法で実施したのと同じように、標準出力を/dev/nullに捨ててあげること。ついでにエラー出力も不要であれば捨ててもいい。

#!/bin/sh

target=`echo $0 | awk -F_ '{print $2}'`

略

val1=awk '{print $1}' /tmp/${target}_result.txt
val2=awk '{print $2}' /tmp/${target}_result.txt
echo "val1.value ${val1}"
echo "val2.value ${val2}"

# 集計する。最後に${target}_resultに出力される。

calculate_command $target > /dev/null 2>&1 &

Munin Masterからtelnetで実行してもすぐに応答がかえるようになった。

$ telnet node-server01 4949
Trying 10.100.133.105...
Connected to node-server01
Escape character is '^]'.
# munin node at node-server01

fetch orignal_targetname1
[出力結果の即時表示]
.
quit
Connection closed by foreign host.
$

ちなみに、集計コマンドのcalculate_commandが標準出力を以下のように結果ファイルにリダイレクトするような作りであれば、問題は発生しない。

calculate_command $target > ${target}_result &

しかし、calculate_command内でファイルに書き込んでいたり、以下のようにsed等で編集していたりしていると、標準出力を/dev/nullに捨ててあげるしかない。

(
calculate_command $target > ${target}_result
sed -i 's/略/略/' ${target}_result
) &