テレビのアニメはどこから来る? / 第81話

第81話:イトは、開いている全員へ送らなかった|既読はいつ付く?

ピコルート第81話。開いたWebSocketへ一斉送信すると、別roomへ誤配した。イトはroom membershipで宛先を絞り、受付・配達・既読を分けます。

チャット配達会話ルーム配達確認既読10分更新

第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
イトが全connectionへのfan-out gateを閉じ、青いroom membership railだけへ一枚のmessage cardを自分の手で送る
open connectionの一覧ではなく、serverが確認したroom membershipから配達先を作る。

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話。

メッセージは何を運ぶ?

この物語を、解説で深める

第81話で生まれた疑問を、解説記事で少し深く見ていきます。物語で感じた不思議さを残したまま、言葉と仕組みを順番に整理しましょう。

チャットの仕組み|メッセージが相手の画面に届く流れを読む