追記:Mastodon v3.1.4以降は仕様が変わっています。続きの記事もあわせてお読みください。DeliveryFailureTrackerで閉鎖したサーバに対処する / DeliveryFailureTrackerがホスト単位になりました
Mastodonのサーバで投稿やブーストが行われると、フォロワーのいるサーバに向けてActivityが配送されますが、何らかの理由で配送できないことがあります。
Mastodonでは、Sidekiq、Stoplight、DeliveryFailureTrackerによって、この配送エラーに対処しています。
Sidekiq
配送を行うActivity毎にActivityPub::DeliveryWorkerというワーカー(ジョブ)を作成し、これをSidekiqのpushキューで処理します。
ActivityPub::DeliveryWorkerでは、ジョブの実行に失敗した場合は16回まで再試行し、それでもダメならあきらめます。
再試行回数が増える度に、次の実行までの時間を長くしていくようになっています。実行間隔は(retry_count ** 4) + 15 + (rand(30) * (retry_count + 1))
という計算式だそうで、15、16、31、96、271、640、1,311、2,416、4,111、6,576、10,015、14,656、20,751、28,576、38,431、50,640秒と増えていきます(これにランダムに秒を加算してジョブ毎のタイミングをずらします)。トータルでだいたい50時間ぐらい頑張ることになりますね。
Stoplight
ひとつだけならジョブ単位での再試行で良いのですが、実際には次々とジョブが作成され、同じ相手に複数の配送が行われます。
すでに何度も失敗している場合、次々に接続しようとするのは無駄です。そこで、失敗回数をカウントして一定回数を超えたら、最初から試さずに失敗するようにします。これがStoplight::Error::RedLight
というエラーです。
送っても大丈夫な状態をGreen
、送らないで待つ状態をRed
、Red
を解除しても良いか判断するためのお試し状態をYellow
として、信号機によって交通整理を行うのがStoplightです。
Mastodonでは、全ての配送ジョブを通じ、同じ相手に10回失敗するとRed
に移行します。Red
は60秒持続し、Yellow
に移行します。Yellow
は一度だけジョブを実行し、成否によりRed
またはGreen
に移行します。
DeliveryFailureTracker
ジョブの成否を監視し、失敗だけで一度も成功しなかった日を記録します。記録が7日になったら、もう配送を行いません。
サービス終了したサーバ、いつまでも死んだままのサーバは、この仕組みにより捕捉されます。
ただし、先方からこちらのinboxに何か配送されてきた場合、生きているらしいと判断して、記録を破棄して配送を復活させます。
Redis
上記の情報は、すべてRedisに記録されています。
特に、DeliveryFailureTrackerの記録は長期的に保持した方が良い性質のものであるため、サーバ移転などの際にうっかり消してしまわないように注意しましょう。