フォルダ名の先頭に連番を振り、毎朝1本ずつ先頭から投稿する。そんな予約投稿キューが、番号が2桁から3桁に変わった途端に、古い記事を3週間放置したまま別の記事ばかり選ぶようになった。エラーは1つも出ていない。原因は文字列順ソートで、直すのは1行。本当に効いたのは、止まったことに気づくための3行のログのほうだった。
連番が桁上がりするときに壊れる定番バグの再現手順と直し方、そして「動いていないこと」に気づくためのログの最小構成。自分のキューや連番ファイルを点検する4つの問い。
私の運用では、投稿待ちの記事をqueueフォルダに93_xxxのような連番つきの名前で積み、毎朝9時のタスクが「先頭の1本」を取り出して公開している。別メディア側のキューで、この「先頭」の決め方が壊れていた。
フォルダ名の番号が2桁から3桁(152_など)に増えたあと、新しく作った記事が毎日公開される一方で、数週間前に積んだ93_〜99_の記事は手つかずのまま残った。公開は毎日成功しているので、画面上は何も異常に見えない。キューの奥に古い記事が溜まっていると気づいたのは、在庫の調査をしたときだった。
取り出し側のスクリプトは、フォルダ名で並べて先頭を取っていた。これは数値ではなく文字列の辞書順になる。辞書順では1文字目から比べるので、1で始まる名前はどれも9で始まる名前より前に来る。
# 辞書順だと、こうなる
100_new-article
152_new-article
93_old-article # ← 最後に回される
99_old-article
2桁の間は偶然うまく動いていた。09_のように0埋めしていれば桁が揃うが、桁が増えた瞬間に前提が崩れる。しかも新しい記事は常に1xx_で始まるため、新しい記事ばかりが選ばれ、古い記事は永遠に順番が来ない。エラーでは止まらず、順番だけが静かに狂う種類のバグだ。
ポイント。連番を名前の文字列として並べていることが問題だった。数値として取り出して並べ直すか、最初から十分な桁数で0埋めしておけば防げる。
名前から先頭の数字を取り出し、整数として比較して並べる。既存の名前を変えずに済むので、今回はこちらを採用した。
0093_のように、将来の桁数まで0埋めして名前を付ける。どんなツールで並べても同じ順になるのが利点だが、既存名の付け替えが要る。
# PowerShell: 先頭の数字を整数にして並べる例
Get-ChildItem $q -Directory |
Sort-Object { [int]($_.Name -replace '^(\d+).*','$1') } |
Select-Object -First 1
どちらでも、「並べ方の前提」を言葉にして確認することが肝心だ。ファイル名に意味を持たせて並び順を頼りにする仕組みでは、桁が変わる瞬間が最も壊れやすい。
ソートを直すのは簡単だった。問題は、3週間のあいだ誰も異常に気づけなかったことだ。毎日公開は成功しており、失敗のログは1行も無い。そこで、取り出しスクリプトを呼び出す側の.batに、最小限の記録を足した。
ログは、起きた失敗を記録するためだけのものではない。「期待どおりに何も起きなかった」ことを証明するためにも要る。これは自動化が黙って死ぬ問題と同じ構造で、自動化は黙って死ぬ——AI同士に見張らせる番犬設計でも別の角度から扱った。
実はこのFLOWブログの予約キューも、番号が現在89番で、あと十数本積めば3桁に入る。もし同じ辞書順の取り出し方のままだったら、100番が積まれた日から同じ事故が起きる。他メディアで踏んだ罠を、まだ踏んでいない自分のキューに先回りして当てはめるのが、運用ネタを記事にする意味でもある。次の4つで点検してほしい。
本記事は筆者自身の運用記録に基づく。コードは概念を示す簡略例で、環境によって調整が要る。