matrix-org / matrix-org/matrix-spec
Retry and queueing UX (SPEC-192)
Nobody has claimed this yet.
- Dominant language
- HTML
- Stars
- 330
- Forks
- 150
- Avg merge
- 2h 21m
- Merged PRs (30d)
- 3
Description
Foreword: This isn't a bug with the SPEC; this is just something that is a "Recommended best practice" for client implementations.
This issue concerns the retry and queueing behaviour of messages which are sent in a room. The example below will be referenced throughout:
A ~~-> B -~~> C ~~- || -~~> D
- A,B,C,D are all events which have been sent by the user.
What happens:
- User hits "Send" on A.
- A transitions to state=SENDING.
- User hits "Send" on B.
- B transitions to state=QUEUED.
- User hits "Send" on C.
- C transitions to state=QUEUED.
- A has failed to send, and transitions to state=FAILED.
- Time passes.
- User hits "Send" on D.
What should happen to events B, C and D in this scenario? Conclusions:
- When A transitions to
state=FAILED, B and C should immediately transition tostate=FAILEDMatthew suggested not transitioning to FAILED but keeping them as QUEUED "so the user can see "ah, B and C are stuck in a queue because A failed"" . The problem with this though is now if I glance up at B and see "queued" I have no idea if I need to do anything to it to make it send. I have to look at A and see if it is failed (then I need to do something) or sending (I don't need to do anything). This is problematic if A B C are not all visible on the screen at once (big messages). . The app starts a timer fornseconds the purpose of the timer is to prevent people typing quickly from accidentally sending a message. e.g. hit send on A B C (all grey sending colour) and typing next message (D) and then A fails which fails B and C (A B C all red now) and I hit send just as I look up to the message list. - When the user hits "Send" on D:
** If >nseconds ago: Transition D tostate=SENDING.
** else: Transition D tostate=FAILED. - All
FAILEDmessages should have areasonenum why they failed. Suggested values:
**NETWORK_ERROR- Message didn't send due to network error. (e.g. couldn't connect)
**SERVER_ERROR- Message didn't send due to a server error (e.g. 500, can include the error code itself somewhere)
**BACKLOG- Message didn't send because the previous message did not send.
**CANCELLED- Message was explicitly cancelled by the user (Why aren't we just removing this from the screen at this point?) - If the user taps an
FAILEDmessage, they can:
* Delete the message locally (removes from the view; won't ever try resending)
*** Resend "from this point onwards" (retries the tapped message and subsequent messages). - If the user taps a
SENDINGmessage, they can cancel it, transitioning it tostate=FAILED. - If the user taps on a
QUEUEDmessage, they can cancel it, or "retry from this point" to make it the head of the queue. Anything before this message will transition toFAILED.
State descriptions:
SENDING- The app is actively trying to send the message. This can include retrying (before the app gives up retrying).SENT- The app has sent the message (200 OK).FAILED- The app failed to send the message. It will not be automatically retried. The user needs to take some form of action to retry this.QUEUED- The app will try to send this message, depending on the outcome of previous messages.
State diagram:
1
<ins>~~--> FAILED <~~</ins>
| 2| ^3 |
| V | |
Msg-~~4~~> SENDING ~~--5~~-> SENT
| ^ |
6| 7| 8|
<ins>~~--> QUEUED~~--</ins>
Reasons for transitions:
1 : => FAILED
* User hits send on a new message whilst timer is < n secs.
2 : FAILED => SENDING
* User explicitly hits resend on this message.
* Previous message was sent.
3 : SENDING => FAILED
* App has given up trying to send this.
* User has explicitly stopped trying to send this.
4 : => SENDING
* User hits send on a message; nothing in queue; no running timer.
5 : SENDING => SENT
* App gets 200 OK for a message.
6 : => QUEUED
* User hits send on a message; an earlier message is being
sent; no running timer.
7 : QUEUED => SENDING
* App sent previous message, now trying this message.
8 : QUEUED => FAILED
* An earlier message was failed.
* User has explicitly stopped trying to send this.
What does the app do when the user submits a new message and the previous message is:
SENDING: Put the new message intoQUEUED.SENT: Put the new message intoSENDING.FAILED: If >nseconds, put new message intoSENDING. If <nseconds, put new message intoFAILED.QUEUED: Put new message intoQUEUED.
(Imported from https://matrix.org/jira/browse/SPEC-192)
(Reported by @Kegsay)
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by reading the state diagram, transition rules, and the imported SPEC-192 reference in this issue. Resolve the competing queue and failure behavior with the maintainers, then identify the specification entry point to update. Done means the retry, queueing, failure reasons, and user actions are specified consistently.
Written by the indexing model from the issue text.
Assessment
- Domain
- backend-api-design
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Needs clarification
- Newbie friendliness
- 25/100