Asopitech With · ボイス・チャットのコミュニティ
Discord オンライン状態 with Alopex Chirps
Discordのオンライン状態は、ボイス・チャットのコミュニティのDiscordで、友だちやメンバーが今オンラインかどうかを見せる機能です。これをAlopex Chirpsを応用して再現すると…?
更新: 2026/10/13
どんなサービスか
Discordでは、ユーザーの名前の横に、オンライン、退席中、取り込み中、オフラインといった状態が出ます。友だちやサーバーのメンバーの状態は、変わるとすぐに相手の画面に反映されます。扱うデータは、ユーザーごとの状態と、その状態を見ている相手です。
通信の組み立て
- ノードのメンバーシップ:ユーザーの接続を受けるサーバーをノードとしてメッシュに入れます。gossipで、どのノードが動いているかを全ノードが知ります。
- 状態の配信:ユーザーの状態が変わったら、そのユーザーを見ている相手がつながるノードへ送ります。宛先が多いときは、全ノードへの配信を使います。古くなってもかまわない状態の通知は、一時的な配信方式で送ります。
- ノードの離脱:ノードが止まると、離脱のイベントが届きます。そのノードにつながっていたユーザーを、まとめてオフラインにできます。
どのユーザーがどのノードにつながっているか、誰が誰の状態を見ているかは、アプリが持ちます。
配置の形
接続を受けるサーバーの各ノードにChirpsを組み込みます。ノードを足すときは、シードのリストから参加させるだけで、ほかのノードに伝わります。
Alopex Chirpsが合う理由
オンライン状態の配信は、ノードどうしの素早い通知と、ノードが止まったことの検知でできています。Chirpsは、送信と全体への配信と、gossipによる故障検知を、同じライブラリで持ちます。
コードで見る
ノードをまたぐ状態変化に一貫した順序を与える、ハイブリッド論理時計の中心だけを取り出したコードです(Rust)。
use alopex_chirps_gossip_swim::hlc::{Clock, LocalHlc};
use std::sync::atomic::{AtomicU64, Ordering};
use std::sync::Arc;
use std::time::Duration;
// 説明用の手動クロック(実際はシステム時計)
struct ManualClock(AtomicU64);
impl Clock for ManualClock {
fn now_millis(&self) -> u64 {
self.0.load(Ordering::SeqCst)
}
}
fn main() {
let skew = Duration::from_secs(1);
// 接続を受ける 2 つのノード A / B。それぞれ論理時計を持つ
let mut a = LocalHlc::with_clock(skew, Arc::new(ManualClock(AtomicU64::new(100))));
let mut b = LocalHlc::with_clock(skew, Arc::new(ManualClock(AtomicU64::new(90))));
// A 側で状態の変化(オンライン→退席)が起きるたびに時計を進める
let online = a.tick();
let away = a.tick();
println!("A: online={online:?} away={away:?}");
// A の変化を B が受け取ると、B の時計は A を追い越す
let seen = b.receive(away).expect("receive");
println!("B receives A: {seen:?}");
// その後 B 側で起きた変化は、必ず A の変化より後に順序づく
let b_change = b.tick();
println!("B next: {b_change:?}");
assert!(b_change > away);
println!("OK: どのノードも、状態変化を同じ順序で解釈できる");
}ハイブリッド論理時計で、ノードをまたいだ状態変化に一貫した順序がつき、最新の状態が全員で一致します。どのノードが動いているか(gossipメンバーシップ)と配信は、本文のとおりChirpsが受け持ちます。
ノードどうしの配信と故障の検知を同じライブラリで扱えるAlopex Chirpsで、オンライン状態の配信を作ってみよう。GitHubのクイックスタートから始められます。