このプロジェクトについて
EDINET(有価証券報告書等)の開示データをもとに、日本株の財務指標・投資判断スコアを日次で算出・公開しているサービスです。
公開サイトはこちら →
https://stocks.happy-life-design.net
前回の記事はこちら →
https://qiita.com/rightcross-ae86/items/3ab1ae2ec23f25be94c9
前回のおさらい
前回、熱暴走の再発防止のために「一定温度で処理を自動一時停止し、温度が下がったら自動で再開する」仕組みを実装した際に見つかった2件のバグ(一時停止コマンドが実行環境の制約で失敗する不具合/対象プロセスの特定ロジックが別プロセスを誤検知する不具合)をご紹介しました。今回は、同じ実装・同じ作業の中で見つかったもう1件、影響が最も大きいバグについて書きます。
見つかった不具合: 現在温度をずっと取り違えていた
現在の温度は、Linuxの温度センサー確認コマンドsensorsの出力をテキストとして解析し数値を抜き出す方式で取得していました。ただしこのコマンドの出力は、1行の中に「現在の実測値」だけでなく「高温警告のしきい値(high)」「危険しきい値(crit)」といった固定の定数も、同じ形式の数値として一緒に含まれています(例: Core 0: +58.0°C (high = +85.0°C, crit = +101.0°C)のような形式)。
数値を抜き出す正規表現は、この行の中にある数値を種類を区別せずすべて拾う作りになっていました。さらに「複数の候補から現在温度を1つに絞り込む」処理として、抜き出した数値をsort -rn | head -1(大きい順に並べ替えて先頭を取る)というシェルの定石で選ぶ実装になっていました。危険しきい値の定数crit = +101.0°Cは実測値がどんな値であっても必ずそれより大きいため、この並べ替えの結果は毎回101.0が選ばれ続けていました。実際の温度が40°Cでも70°Cでも、システムが認識する「現在温度」は常に101.0°Cという固定値になっていたということです。
なぜ気づきにくかったか: 一時停止側は「たまたま」正しく見えていた
一時停止の条件は「95°C以上になったら止める」というものでした。誤認識していた101.0°Cは95°Cを常に上回るため、一時停止の判定自体は見かけ上いつも正しく成立していました。つまりこのバグは、動作確認で「一時停止は正常に動いている」ことを見ただけでは発覚しない性質のものでした。
問題は再開の条件でした。「85°C以下になったら再開する」という条件に対し、誤認識される値は常に101.0°Cのため、85°C以下になることは構造的に一度もあり得ません。つまりこの機能を実装した最初の時点から、自動再開だけが一度も動作しない作りになっていたことになります。安全装置としては、止める方は機能するのに戻す方だけが完全に死んでいた、という状態です。
(技術的な補足)何が起きていたか・どう直したか
対象のスクリプトはこの日のセッション内でその場限りに作成したもので、現在はgit管理外のため実物は残っていません。以下は「sensors出力を正規表現で抽出しsort -rn | head -1で最大値を採用していた」という記録をもとに再現したイメージコードです(実際の変数名・実装の細部までは一致しない可能性があります)。
sensorsコマンドの出力は、CPUコアごとに実測値・high(警告しきい値)・crit(危険しきい値)の3つの数値が1行に並ぶ形式です。
$ sensors
coretemp-isa-0000
Package id 0: +58.0°C (high = +85.0°C, crit = +101.0°C)
Core 0: +55.0°C (high = +85.0°C, crit = +101.0°C)
修正前(再現コード)
# sensorsの1行から数値をすべて拾ってしまう
CURRENT_TEMP=$(sensors | grep "Package id 0" \
| grep -oE '[0-9]+\.[0-9]+' \
| sort -rn | head -1)
grep -oE '[0-9]+\.[0-9]+'は行内の数値(58.0 / 85.0 / 101.0)を種類の区別なくすべて拾います。sort -rn | head -1で並べ替えた結果、常に最大の101.0(crit)が「現在温度」として採用されていました。
修正後(再現コード)
# ":"の直後、"("より前の実測値部分だけを抽出する
CURRENT_TEMP=$(sensors | grep "Package id 0" \
| grep -oE ':\s*\+[0-9]+\.[0-9]+' \
| grep -oE '[0-9]+\.[0-9]+')
実測値の直後にある(より前の範囲だけを対象にすることで、high・critの定数がそもそも抽出候補に入らなくなり、sortによる誤選択も同時に解消されます。修正後は実際に温度が変化する状況を再現し、一時停止(95°C到達)→温度低下→自動再開(85°C以下)まで一連の流れが正しく動作することを確認しました。
次にやること
このバグは、実際の高温状態で本格的に使う前の動作確認の中で発見・修正できたため、幸い実害はありませんでした。今回の候補D(自作バグ3件)はこれで一区切りです。次は、これとは別に見つかっている既存パイプラインの不具合の横展開など、他の候補を扱う予定です。
まとめ
「一時停止」と「再開」という対になる2つの条件のうち、片方だけが見かけ上正しく動いていたために発覚が遅れかけたバグでした。安全装置のテストでは、個々の条件が単独で正しそうに見えることと、実際に想定する一連の流れ(止める→下がる→戻る)が最後まで通ることは別問題だと痛感しました。気になる点・ご質問があればコメントでお知らせください。