鳴らないSOSは、順番のせいだった

画面には「かおり が緊急通報しました」と出ている。なのに、誰の電話も鳴っていない。 7月25日に安全デバイスの機能を頭から洗い直したとき、いちばん冷や汗が出たのがこの経路だった。 原因は難しいものではなく、処理の順番だった。

うちのデリヘル管理アプリでSOSが押されると、通報が1件起票されて、通知の仕事がキューに積まれる。 その仕事がやることは3つ。店の画面に出すお知らせの行を作る、開いている画面へ赤いポップを即時に配信する、 そして端末に登録した連絡先へSMSと電話を飛ばす外部連絡の仕事を、もうひとつ別にキューへ積む。 作った当初は、この順番で書いてあった。お知らせ、配信、外部連絡。

配信が死ぬと、電話まで道連れになる

画面への即時配信は、配信用のサーバーへその場で投げる同期の処理だ。 そのサーバーが落ちていると、ここで例外が出る。例外が出た時点で通知の仕事は途中で止まるので、 3つ目の外部連絡はキューに積まれない。SMSも電話も、一本も出ていかない。 通知の仕事は失敗すると3回までやり直すが、サーバーが落ちたままなら3回とも同じ行で同じ例外が出る。 店が気づくまで鳴らし続けるための再通知の巡回も、同じ場所で同じように止まる。

たちが悪いのは、1つ目のお知らせの行だけは先に作られていることだ。 画面を見れば「緊急通報しました」と書いてある。通知した形跡はある。それで誰の電話も鳴っていない。 配信サーバーが止まることなど普段はないから、テスト運用でも一度も踏まなかった。 コードを順に読み直す調査をしなければ、本番で初めて踏んでいたと思う。

直し方は順番を入れ替えるだけだった。 通報が緊急のものなら、まず外部連絡の仕事をキューへ積む。何より先に、これを確実に積む。 そのあとでお知らせの行を作り、画面への配信は例外が出ても握って記録するだけにして、 最後に「通知した時刻」を書く。配信が失敗しても、電話とSMSとお知らせと時刻は生き残る。 配信の処理がわざと例外を投げる状態を作り、それでも外部連絡が積まれてお知らせと時刻が残ることを確かめるテストを一緒に置いた。

安全デバイス管理の端末の運用設定。測位間隔とSOSの各チェックの下に「SOS通報先(最大10件)」の節があり、店舗・ドライバー・警備の3件の連絡先に、SMSと通話のチェックが並ぶ。SOS時の架電とSMSはここに登録した番号だけに行われ、1件目が最優先で架電されるという説明がある
SOSの通報先。この一覧へのSMSと電話が、何があっても最初にキューへ積まれる側の処理になった(画面はデモデータです)。

なぜ外部連絡だけ別の仕事なのか

そもそも外部連絡を別の仕事に切り出したのは、7月の頭だ。 端末からのメッセージを受ける処理の中で、連絡先の数だけ電話の回線へ往復していると、返事が遅れる。 返事が遅れると、端末のメッセージを中継する側が「届いていない」と判断して同じメッセージを送り直してくる。 それを避けるために、お知らせと配信は同期のまま残し、時間のかかる外部連絡だけをキューへ逃がした。 その切り出しが、結果として「順番を変えれば守れる」形を先に作っていたことになる。

同じ日に、連絡先の側にも穴を見つけた。電話番号を国内の書き方のまま回線へ渡すと全件が弾かれるのに、 それが警告のログにしか出ていなかった。保存のときに国際形式へ直して受け付け、送る直前にももう一度直す。 送信に失敗した連絡先が1件でもあれば、連絡先がそもそも空のときと同じく、店へのお知らせの行を残すようにした。

宿題がひとつ残っている。その「送れなかった」お知らせは、いまは行が残るだけで、 受付画面の上に出る帯の種類にまだ入れていない。通報そのものは赤いポップで届くので、致命的ではない。 ただ「鳴ったつもりで鳴っていない」を潰した話の締めとしては、帯に出すところまでやって初めて終わりだと思っている。