問わない — ポーリングが無駄であることより悪い理由
5 分4 編目まで、最新の値を知るには問わねばならなかった。一秒ごとに問うか、人が更新するか。
購読する
client.onResourceUpdated((uri) {
// The notification says only that it changed. Read to learn what to.
seen.add(uri);
stdout.writeln('notified: $uri');
});
await client.subscribeResource('desk://waiting');そして値が変わるようにしてみる。
await client.callTool('desk.admit', {'count': 1});subscribed to desk://waiting
notified: desk://waiting
after the notification, reading gives {waiting: 2}
notifications received: 1通知は uri しか運ばない
ハンドラが受けるのは uri ひとつだ。何人になったかは来ない。サーバー 6 編目で値を載せない理由を扱ったが、受ける側ではそれが 読まねばならない という意味になる。
final now = await client.readResource('desk://waiting');もう一往復するのが損に見えるが、これが常に正しい。通知が何個来ようと順序がどうであろうと、読んだ時点の値 が最新だからだ。
ポーリングの本当の問題
ポーリングを避ける理由として、たいてい資源が挙げられる。一秒ごとにサーバーを叩けば無駄だ。
それは副次的である。本当の問題は、二度問う間を見られないことだ。
09:00:00 ポーリング → waiting 3
09:00:00.4 二人入場 → waiting 1
09:00:00.7 一人到着 → waiting 2
09:00:01 ポーリング → waiting 2画面は 3 から 2 へ行った。1 だった瞬間を見ていない。 最終値だけが必要なら構わないが、「0 になったら通知」のような規則があれば、その規則は発動しない。
間隔を縮めても消えない。狭くなるだけだ。そして狭めるほど無駄が増える。
終わったら解く
await client.unsubscribeResource('desk://waiting');画面が閉じたら購読を解く。解かなければサーバーが居ない相手に送り続ける。
実機の編の ESP32 はこれを 画面定義の中に 入れていた — onReady で購読、onDestroy で解除。生命周期が画面に書かれていれば、クライアントは忘れられない。
検証 — ポーリングなら失敗
grep -q 'notified: desk://waiting' captures/s5.txt || die "no notification arrived"
grep -q 'notifications received: 1' captures/s5.txt || die "wrong notification count"
grep -q 'reading gives {waiting: 2}' captures/s5.txt || die "the read after the notification was stale"
# Polling would show up as a timer; the claim is that there is none.
grep -qE 'Timer|periodic' bin/step5.dart && die "it is polling, not subscribing"Timer や periodic がコードにあれば失敗する。結果だけを見ればポーリングと購読は同じに見えるから だ — どちらも画面に 2 が出る。
通知の個数を数えるのも同じ理由だ。0 なら来ていないし、複数なら重複購読である。
五編が終わった
step1 connected to Course 1.0.0
step2 tools: desk.admit
resources: ui://desk, desk://waiting
step3 admit 1 -> {waiting: 2}
admit 99 -> isError=true "only 2 waiting"
step4 ui://desk — 546 B, 6 lines, type "page", title "Desk"
step5 notifications received: 1 · after the notification, reading gives {waiting: 2}
5 steps · each checked against its own claim · driven against the course serverモックのサーバーが無い。 五段階すべて、サーバー講座で作ったあのサーバーを実際に立てて繋ぐ。だから二つのトラックがずれればここで引っかかる — 実際に 3 編目で一度引っかかった。
自分で動かす
cd content/sample/course-client
dart pub get
bash verify.sh # 五段階すべて
dart run bin/step5.dart持ち帰るもの
onResourceUpdated+subscribeResource— ハンドラを先に掛けてから購読する- 通知の後に読む — 通知は uri しか運ばない
- ポーリング禁止の検査 — 結果が同じに見えるのでコードを見る
次のトラック
サーバーとクライアントが立った。次は画面そのもの — JSON のひと塊がどうやって画面になるのか。
サンプルを実行する
makemind-academy/course_client/git clone https://github.com/makemind-academy/course_client cd course_client dart pub get (cd course-server && dart pub get) dart run bin/step5.dart