构建

来处理状态吧——动值,别动画面

作者: makemind · 2026年1月23日

两周前那块叫号屏停在 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
NOW SERVING 41 — 3 waiting · issued 44
NOW SERVING 41 — 3 waiting · issued 44

叫两次。

called twice -> now 43, 1 waiting
NOW SERVING 43 — 1 waiting · issued 44
NOW SERVING 43 — 1 waiting · issued 44

43,还剩一个。 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
NOW SERVING 41 — 0 waiting · issued 41
NOW SERVING 41 — 0 waiting · issued 41

回到了 41。 等待人数也是 0。

这不是缺陷,而是这个样例实际就是这么做的这一事实。状态在 服务端进程的内存里,显示装置是用 stdio 接的,所以显示装置一死,服务端进程跟着一起死。队列跟着进程一起没了。

the number did NOT survive: this counter keeps its queue in memory,
so the process ending took the queue with it

此内容需要开发者或更高等级

登录并升级您的方案即可继续阅读。

查看方案
Twitter