2주 전 번호판은 41에서 안 움직였다. 버튼이 도구 이름을 부르는데 그 도구가 없었다.
이번엔 붙인다. 그런데 붙이기 전에 정해야 하는 게 하나 있다 — 그 숫자를 누가 들고 있나.
왜 이게 질문인가
화면이 들고 있으면 코드가 짧다. 버튼을 누르면 화면 안의 값이 하나 올라가고, 화면이 다시 그려진다. 서버는 몰라도 된다.
그리고 패널을 하나 더 달면 그날 끝난다. 대기실 앞에 하나, 창구 옆에 하나. 각자 자기 숫자를 세니까 둘이 다른 번호를 띄운다. 손님은 앞에 있는 걸 보고, 직원은 옆에 있는 걸 본다.
번호는 화면의 것이 아니다. 카운터의 것이다.
카운터가 들고 있다
그래서 상태는 서버 쪽에 있다.
var _now = 41;
var _issued = 41;
now 는 부르고 있는 번호, issued 는 마지막으로 뽑아 준 번호다.
도구 두 개가 이 둘을 만진다.
server.addTool(
name: 'queue.next',
description: 'Call the next number',
inputSchema: const {'type': 'object', 'properties': {}},
handler: (args) async {
// The counter refuses to pass the last ticket it issued. Without this
// the display runs ahead of the room and calls numbers nobody holds.
if (_now >= _issued) return _state(notice: 'nobody is waiting');
_now++;
return _state(notice: 'called $_now');
},
);
거절부터 확인한다
붙이자마자 제일 먼저 확인한 게 잘 되는 경우가 아니라 안 되는 경우다.
아무도 안 기다리는데 「Call next」 를 누른다.
pressed Call next -> now 41 ("nobody is waiting")
the counter refused: it will not call past the last ticket issued
41에서 안 올라갔다. 이 검사가 없으면 화면이 방보다 앞서 나간다 — 아무도 안 들고 있는 42번을 부르고, 43을 부르고, 그러다 진짜 손님이 42를 들고 왔을 때 이미 지나가 있다.
이제 움직인다
표를 세 장 뽑는다.
three tickets taken -> issued 44, 3 waiting

두 번 부른다.
called twice -> now 43, 1 waiting

43이고 1명 남았다. 41 + 2 = 43, 44 − 43 = 1. 화면이 계산한 게 아니라 카운터가 계산해서 보낸 값이다.
화면 쪽 코드에는 41도 +1도 없다. {{now}} 와 {{waiting}} 자리만 있다.
뽑았다 꽂는다
여기가 이번 글에서 제일 중요한 부분이다.
번호판은 뽑힌다. 전원이 나가고, 패널을 바꾸고, 청소하다 케이블을 건드린다. 그때 무슨 일이 일어나는지 확인하지 않으면 모른다.
그래서 연결을 끊고 다른 표시장치를 붙였다.
display disconnected — the server process ends with it
a different display connects
it reads 43/44 before, 41/41 after

41로 돌아갔다. 대기 인원도 0이다.
이건 버그가 아니라 이 샘플이 실제로 이렇게 만들어져 있다는 사실이다. 상태가 서버 프로세스의 메모리에 있고, 표시장치를 stdio로 붙였으니 표시장치가 죽으면 서버 프로세스도 같이 죽는다. 큐가 프로세스와 함께 사라졌다.
the number did NOT survive: this counter keeps its queue in memory,
so the process ending took the queue with it