第80話で開いた一本のconnectionへ、三枚のmessage cardが滑り込んだ。
イトは最初の一枚をつかむ。
青いroomで、ユイだけに見せるtest messageだった。
serverには、三人のconnectionがOPENで並んでいる。
イトはsend to all open connections leverへ手を掛けた。
「開いている道へ全部流せば、すぐ届くよね」
leverを倒した瞬間、青いcardが二つのviewer trayへ入った。
一つはユイ。
もう一つは、別のamber roomにいるマコト。
マコトのscreenにも、青いroomのtest messageが出ていた。
connectionは、宛先ではなかった
ユイとマコトは、どちらもserverへ接続している。
けれど、二人が同じroomにいるわけではない。
room-blue membership v7
Ito
Yui
room-amber membership v3
Ito
Makoto
送ったmessageはroom-blueのm-204。
期待したrecipientはユイ一人。
all-open-socketsへbroadcastした結果は、二人だった。
expected recipients Yui
actual recipients Yui, Makoto
wrong recipients 1
WebSocketは、必要なときに双方からmessageを流せる。
誰へ流してよいかまでは決めない。
open connectionをrecipient listとして使うと、別roomの人まで同じmessageを受け取る。
イト
つながっている人と、見ていい人を同じにしてしまった
ユイ
connectionは今送れる道です。room membershipは送ってよい範囲です
マコト
あとから消しても、見られなかったことには戻せないね
これはclosed labのtest messageだった。
それでも、wrong recipient 0のまま次へ進む必要がある。
次の試行では、ユイをいったんofflineにする。
server accepted、recipient device delivered、human readを一つのlampへまとめず、どこまで進んだかも残す。
三つの配達方法
イトはglobal broadcast leverを戻し、三枚の案を並べた。
A:すべてのOPEN connectionへbroadcastする
onlineの人へは速く届く。
しかしroom外のマコトにも届き、offlineのユイへは残らない。
B:clientが送ってきたrecipient listを、そのまま信じる
sender側で宛先を作れる。
けれど、古いmember listや書き換えられたlistをserverが信じると、いまのroom membershipとずれる。
C:serverがsenderとroom membershipを確認し、room eventとして保存してからmemberだけへ配る
serverが持つcurrent membershipで、イトがroom-blueへsendできるかを確認する。
messageをroom historyへ一件appendする。
online memberへfan-outし、offline memberには再接続後のcatch-upで渡す。
ユイ
Cなら、いまofflineでもroom historyからあとで受け取れます
マコト
私はserverへつながっていても、blue roomのmemberではないから対象外だ
イト
Cにする。connectionの一覧ではなく、roomのmemberから配達先を作る
Picoは三枚の案に触れない。
wrong trayへ入った青いcardと、二つのroom membership boardをcyan lightで照らしただけだった。
イトがglobal broadcastを閉じた
イトはsend to all open connections leverをOFFへ戻した。
代わりに、server counterへ三つのgateを一つずつ組む。
1. authenticate sender
2. authorize sender for current room membership
3. append one room event, then fan-out to current members
message m-204をもう一度、closed fixtureへ入れた。
senderはイト。
roomはroom-blue。
server-owned membership v7には、イトとユイだけがいる。
マコトのroom-amber connectionはOPENのままにする。
それでも、blue messageのrouteからは外れた。
sender authorized yes
room event appended 1
Makoto deliveries 0
wrong recipients 0

server acceptedは、相手が読んだ印ではない
次の試行では、ユイのdevice connectionをOFFLINEにした。
イトがm-205をroom-blueへ送る。
+120 ms、serverはsenderとmembershipを確認し、room historyへappendした。
sender側の最初のlampはacceptedになった。
server accepted 1
Yui device delivered 0
Yui human read 0
イトはread lampを点けようとしたが、指を止めた。
serverに保存されたことと、ユイのdeviceへ届いたことは別。
deviceへ届くことと、ユイ本人が見たことも別だった。
XMPPのdelivery receiptも、intended recipientが管理するclientへ届いたことを示す仕組みで、人間がreadまたはunderstoodした証明にはしない。
どのserviceがどの時点をreadと呼ぶかも、applicationの設計で変わる。
offline memberへ、あとから届けた
+420 ms、ユイのdeviceがreconnectした。
serverはroom-blueのlast accepted eventを照合し、未取得のm-205を一件だけ送る。
+460 ms、ユイのdevice trayへcardが入った。
+500 ms、deviceがm-205 receivedのreceiptを返す。
そこで初めて、sender側のdelivered lampを点けた。
server accepted 1
Yui device delivered 1
Yui human read 0
Makoto deliveries 0
イト
deliveredになった。でも、ユイはまだroomを開いていない
ユイ
deviceのtrayに入ったところまでですね
マコト
receiptが戻らないだけで、必ず未配達とも決められない。返事自体が失われる場合もある
delivery receiptは、guaranteed deliveryの魔法ではない。
recipient clientがreceiptを返さない設定かもしれない。
receiptのreturn pathが切れるかもしれない。
だからreceiptがない=必ず未配達と決め、同じmessageを無条件に増やすこともできない。
retryとduplicate suppressionは、message identityを含む別の設計が要る。
readは、ユイのactionのあとに来た
+900 ms、ユイがroom-blueを開いた。
screenにm-205が表示される。
ユイは最後に見たeventを示すread receiptをserverへ送った。
+940 ms、sender側のread lampが点く。
server accepted 1
Yui device delivered 1
Yui human read 1
Makoto deliveries 0
wrong recipients 0
read lampを点けたのは、WebSocket connectionがOPENだったからではない。
ユイのapplicationが、どのeventまでread扱いにしたかを返したからだった。
入力中、通知、未読数も同じ本文ではない。
それぞれ別のstate eventとして、誰にどこまで見せるかを決める。
一つのlampへまとめない
イトは四つのtrayを並べた。
local queuedは、sender deviceにまだある。
server acceptedは、serverがroom eventとして受け付けた。
client deliveredは、recipient clientが受け取ったreceiptがある。
human readは、そのserviceが定めたread actionのreceiptがある。
変化を一つずつ観測すれば、「送信済みなのに既読がつかない」を一つの故障名にしなくてよい。
まず、どのtrayまで進んだかを見る。
room外へ一件でも出たら、配達を止めてmembership / authorizationを確認する。
本文だけのcardは、server counterで止まった
最終結果は、room event 1。
ユイへのdelivered 1、read 1。
マコトへのdelivery 0。
wrong recipient 0。
イトはglobal broadcast leverへ封印ringを掛け、blue room railだけを残した。
そこへ次のmessage cardが来た。
表には「写真を送る」とだけ書いてある。
裏には、何もない。
roomもsenderもmessage IDも、attachmentの置き場所も見つからなかった。
server counterは、cardをどのhistoryへappendすればよいか決められない。
イト
配達路は選べても、このcardが何者か分からない
ピコ
次は、messageが本文のほかに何を持って運ばれるかを見よう
Picoは空欄を埋めない。
止まった一枚と、イトが確認する四つのempty field slotだけを照らした。
次回、ピコルート第82話。
メッセージは何を運ぶ?

