묻지 않는다 — 폴링이 낭비인 것보다 더 나쁜 이유
5 분4편까지 최신 값을 알려면 물어야 했다. 1초마다 묻거나, 사람이 새로고침하거나.
구독한다
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');한 번 더 왕복하는 게 손해 같지만, 이게 항상 옳다. 알림이 몇 개 오든 순서가 어떻든, 읽은 시점의 값이 최신이기 때문이다.
폴링의 진짜 문제
폴링을 안 쓰는 이유로 대개 자원을 든다. 1초마다 서버를 두드리면 낭비다.
그건 부차적이다. 진짜 문제는 두 번 묻는 사이를 못 본다는 것이다.
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