Skip to content

MSC4140: Cancellable delayed events - #4140

Merged
turt2live merged 267 commits into
mainfrom
toger5/expiring-events-keep-alive
Sep 8, 2026
Merged

turt2live merged 267 commits into
mainfrom
toger5/expiring-events-keep-alive

Conversation

@toger5

@toger5 toger5 commented May 7, 2024

Copy link
Copy Markdown
Contributor

Rendered

This could also supersede MSC2228 (by making it possible to send a redaction with the /send endpoint. This is the case as mentioned here)

Implementations

Known differences between current implementations and the proposal

Implementations in Element Call via the Widget API

These are only informational and shouldn't be relevant for the proposal process. The MSC doesn't depend on widgets and widgets are themselves not part of the spec.


SCT stuff:

MSC checklist

FCP tickyboxes

Designated reviewers:

@toger5
toger5 force-pushed the toger5/expiring-events-keep-alive branch 2 times, most recently from 0eb1abc to 8bf6db7 Compare May 8, 2024 15:49
Comment thread proposals/4140-expiring-events-with-keep-alive-endpoint.md Outdated
Comment thread proposals/4140-expiring-events-with-keep-alive-endpoint.md Outdated
Comment thread proposals/4140-expiring-events-with-keep-alive-endpoint.md Outdated
Comment thread proposals/4140-expiring-events-with-keep-alive-endpoint.md Outdated
Comment thread proposals/4140-expiring-events-with-keep-alive-endpoint.md Outdated
Comment thread proposals/4140-expiring-events-with-keep-alive-endpoint.md Outdated
Comment thread proposals/4140-expiring-events-with-keep-alive-endpoint.md Outdated
Comment thread proposals/4140-expiring-events-with-keep-alive-endpoint.md Outdated
Comment thread proposals/4140-expiring-events-with-keep-alive-endpoint.md Outdated
@turt2live turt2live changed the title Draft for expiring event PR MSC4140: Expiring events with keep alive endpoint May 9, 2024
@turt2live turt2live added proposal A matrix spec change proposal. Process state. A-Client Server Client-Server API kind:feature MSC for not-core and not-maintenance stuff needs-implementation This MSC does not have a qualifying implementation for the SCT to review. The MSC cannot enter FCP. labels May 9, 2024
@toger5
toger5 force-pushed the toger5/expiring-events-keep-alive branch 2 times, most recently from c82adf7 to 54fff99 Compare May 10, 2024 18:08
Comment thread proposals/4140-delayed-events-futures.md Outdated
Comment thread proposals/4140-delayed-events-futures.md Outdated
Comment thread proposals/4140-delayed-events-futures.md
Comment thread proposals/4140-delayed-events-futures.md Outdated
Comment thread proposals/4140-delayed-events-futures.md Outdated
Comment thread proposals/4140-delayed-events-futures.md Outdated
Comment thread proposals/4140-delayed-events-futures.md Outdated
Comment thread proposals/4140-delayed-events-futures.md Outdated
Comment thread proposals/4140-delayed-events-futures.md Outdated
Comment thread proposals/4140-delayed-events-futures.md Outdated
Comment thread proposals/4140-delayed-events-futures.md Outdated
Comment thread proposals/4140-delayed-events-futures.md Outdated
Comment thread proposals/4140-delayed-events-futures.md Outdated
Comment thread proposals/4140-delayed-events-futures.md Outdated
Comment thread proposals/4140-delayed-events-futures.md Outdated

@hughns hughns left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some suggestions for clarity.

Comment thread proposals/4140-delayed-events-futures.md Outdated
Comment thread proposals/4140-delayed-events-futures.md Outdated
Comment thread proposals/4140-delayed-events-futures.md Outdated
Comment thread proposals/4140-delayed-events-futures.md Outdated
Comment thread proposals/4140-delayed-events-futures.md Outdated
Comment thread proposals/4140-delayed-events-futures.md Outdated
Comment thread proposals/4140-delayed-events-futures.md Outdated
Comment thread proposals/4140-delayed-events-futures.md Outdated
Comment thread proposals/4140-delayed-events-futures.md Outdated
Comment thread proposals/4140-delayed-events-futures.md Outdated
Comment thread proposals/4140-delayed-events-futures.md Outdated
@toger5
toger5 force-pushed the toger5/expiring-events-keep-alive branch from 95c855f to f3bf66d Compare June 3, 2024 18:26
Comment thread proposals/4140-delayed-events-futures.md Outdated
Comment thread proposals/4140-delayed-events-futures.md Outdated
Comment thread proposals/4140-delayed-events-futures.md Outdated
@toger5
toger5 force-pushed the toger5/expiring-events-keep-alive branch 2 times, most recently from 96409b1 to 412464a Compare June 5, 2024 22:18
@toger5
toger5 force-pushed the toger5/expiring-events-keep-alive branch from 412464a to 1140ce9 Compare June 5, 2024 22:18
Comment thread proposals/4140-delayed-events-futures.md Outdated
Comment thread proposals/4140-delayed-events-futures.md Outdated
Comment thread proposals/4140-delayed-events-futures.md Outdated
Comment thread proposals/4140-delayed-events-futures.md Outdated
Instead just say more clearly that the error returned is the same as
what would have been returned for a non-delayed event request
Network errors on the endpoint would cause responses to be lost if they
were to be discarded by the server

@erikjohnston erikjohnston left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Otherwise I'm happy

[capability](https://spec.matrix.org/v1.19/client-server-api/#capabilities-negotiation) named `m.delayed_events`, via
the values of non-negative integer valued fields named `max_delay_ms` and `max_scheduled` respectively.
For any of these limits enforced by the server, its representative field MUST be present in the capability.
If the server doesn't enforce one of these limits, its representative field MUST be absent from the capability.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This framing does mean it's impossible for a server to say that delayed events are disabled. I'm not sure that is something we want to support, but equally feels odd. I'm not sure if it's worth doing anything about it though

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It can communicate disabled delayed events by responding with:

{
  "capabilities": {
    "m.delayed_events": {
      "max_delay_ms": 0,
      "max_scheduled": 0
    }
  }
}

Even including only one of the max_ fields would be sufficient, as it's enough for either one of them to be 0 to mean that delayed events are disabled.

Does that cover your concern?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mmm, true I suppose. Though if we want clients to consider 0 to mean disabled then that's something we should be specific. While technically a limit of 0 is the same, it needs to be handled specially by clients (i.e. this operation will never work no longer how long we wait).

OTOH I'm not sure if we want to allow delayed events to be disabled by the server? I guess that is the fundamental question, and we should either explicitly allow or deny 0 as the limit.

(This is a very low severity thing)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While technically a limit of 0 is the same, it needs to be handled specially by clients (i.e. this operation will never work no longer how long we wait).

Aha, this is what that "special case" I was banging on about was for. It landed as ec7cbfd.

OTOH I'm not sure if we want to allow delayed events to be disabled by the server?

IMO there's no harm to allow disabling it, especially if server configs already allow you to constrain it (why not allow constraining it all the way to 0?).

As another point, this section should also specify what clients should assume if the m.delayed_events capability is absent entirely (not just its fields).

af63014 does so, and also explicitly specifies what 0 limits mean.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suppose managing delayed events will cause some amount of load on the server. I suppose it's low but technically allowing an admin to disable it seems reasonable to me.

Even if we don't allow 0. A value of 1ms would still mean the feature is effectively disabled from a client's perspective.

Comment thread proposals/4140-delayed-events-futures.md Outdated
AndrewFerr and others added 2 commits August 25, 2026 11:07
Evaluate at both schedule & send time

Co-authored-by: Erik Johnston <erik@matrix.org>
@dbkr

dbkr commented Aug 26, 2026

Copy link
Copy Markdown
Member

@mscbot resolve open comment threads

for the sake of consistency
@mscbot

mscbot commented Sep 2, 2026

Copy link
Copy Markdown
Collaborator

🔔 This is now entering its final comment period, as per the review above. 🔔

@ara4n

ara4n commented Sep 2, 2026

Copy link
Copy Markdown
Member

So I've gone through the whole thing (and a bunch of the old threads) and it makes sense - it's an alternative approach to my proposal at #3277 but there's a meaningful difference between asking your local HS to maybe send an event in future... versus asking your local HS to send an event right now, which servers should only reveal to their clients in future.

I've approved it for FCP, but with one minor proviso: i really tripped over the "Delegating scheduled delayed events" section in Alternatives... because it's listed as an alternative (having previously been part of the main proposal), and yet MatrixRTC explicitly depends on delegated delayed events to function sensibly, by letting SFUs explicitly trigger delayed leave events when users leave a call.

Now, it turns out that the way that works is that MSC4195 (LiveKit transport for MatrixRTC) specifies how a homeserver can cancel MSC4140 delayed events on behalf of the LiveKit SFU if the SFU knows that a user has dropped (the whole /_matrix/client/v1/rtc/livekit/delegate_delayed_leave mechanism). But it'd be good to explicitly mention this to avoid others getting confused. Something like:

Delegation of delayed events to other entities was originally part of this MSC, but descoped as an alternative given these complexities. However, a simplified version of it is reintroduced in MSC4195 which allows a user's homeserver to act on behalf of the user in response to updates from a LiveKit SFU.

It also feels weird that the MatrixRTC delegation approach has ended up as livekit-specific in the LK transport MSC, when there's nothing livekit specific about it? However, that's more a point for MSC4195.

Comment thread proposals/4140-delayed-events-futures.md
@Johennes

Johennes commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

[...] But it'd be good to explicitly mention this to avoid others getting confused. Something like:

Delegation of delayed events to other entities was originally part of this MSC, but descoped as an alternative given these complexities. However, a simplified version of it is reintroduced in MSC4195 which allows a user's homeserver to act on behalf of the user in response to updates from a LiveKit SFU.

I have applied this in https://github.com/matrix-org/matrix-spec-proposals/pull/4140/changes#r3922947293.

Comment thread proposals/4140-delayed-events-futures.md
@mscbot

mscbot commented Sep 7, 2026

Copy link
Copy Markdown
Collaborator

The final comment period, with a disposition to merge, as per the review above, is now complete.

@richvdh

richvdh commented Sep 7, 2026

Copy link
Copy Markdown
Member

Slightly belatedly, I'm going to open a concern to track a resolution to @jevolk's comment.

(per the process: "a member of the Spec Core Team can raise a concern and block FCP from completing. This will not reset or pause the 5 day FCP timer, but FCP will not conclude until all concerns have been resolved")

We're all going to pretend that I did this an hour ago.

@mscbot concern comments from @jevolk regarding T&S

@turt2live

Copy link
Copy Markdown
Member

Talked with @richvdh out of band:

@mscbot resolve comments from @jevolk regarding T&S

@mscbot

mscbot commented Sep 8, 2026

Copy link
Copy Markdown
Collaborator

🔔 This is now entering its final comment period, as per the review above. 🔔

@Johennes Johennes mentioned this pull request Sep 11, 2026
4 tasks
- `delayed_since_ts` - Required. The timestamp (as Unix time in milliseconds) when the delayed event was scheduled or
last restarted.
- `content` - Required. The content of the delayed event.
This is the body of the original `PUT` request, not a preview of the full event after sending.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Johennes Johennes Sep 14, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suppose what is meant here is the content object from the body of the original PUT request. Anything else would be fairly nonsensical. We should replace this with e.g.

This is the content property from the body of the original PUT request, not a preview of the full event after sending.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@turt2live can we still apply this clarification?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure - a dedicated PR would be best.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This now lives in #4542.

}
```

If the capability is absent, clients SHOULD assume that delayed events are disabled / not supported by the server,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Line 132 lets a capable server that doesn't enforce limits omit the capability itself.

If the server enforces none of these limits, the capability MAY be omitted entirely instead of having an empty body.

Line 147 tells the client that absence means disabled.

If the capability is absent, clients SHOULD assume that delayed events are disabled / not supported by the server,

The feature is not discovered.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good spot. Fix in #4542.

Comment on lines +615 to +616
To mitigate the risk of users flooding the delayed events database, homeservers MUST impose limits on the number and
timeout duration of scheduled delayed events. The exact limits are left as an implementation detail.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tip

  • MAY enforce a maximum delay.

The homeserver MAY enforce a maximum allowed delay for delayed events. This limit is

Warning

  • SHOULD enforce a maximum scheduled count.

The homeserver SHOULD enforce a limit of how many delayed events a user may have scheduled at once
to provide mitigation against both the
[High Volume of Messages](https://spec.matrix.org/v1.19/appendices/#threat-high-volume-of-messages) and
[Resource Exhaustion](https://spec.matrix.org/v1.19/appendices/#threat-resource-exhaustion) threats.

Caution

  • MUST enforce a maximum delay and maximum scheduled count !

To mitigate the risk of users flooding the delayed events database, homeservers MUST impose limits on the number and
timeout duration of scheduled delayed events. The exact limits are left as an implementation detail.

Warning

  • SHOULD enforce a maximum scheduled count.

threat. The homeserver SHOULD apply rate-limiting to both the scheduling of delayed events and the later sending to
mitigate this risk, as well as limiting the number of scheduled events a user can have at any one time.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


If the target delayed event is already finalised with an outcome that conflicts with the `action`, i.e.
if the `action` is `send` or `restart` and the delayed event has already been cancelled,
or if the `action` is `cancel` and the delayed event has already been sent,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
or if the `action` is `cancel` and the delayed event has already been sent,
or if the `action` is `cancel` or `restart` and the delayed event has already been sent,

The intent looks settled already: #4140 (comment) proposed 409 for restart on a sent or cancelled event, and 1e18fa2 ("Return 409 Conflict on any conflicting action") implemented it but listed only cancel for the sent case, so this reads as a transcription slip rather than a decision.

Line 204 gives send on a sent event a 200. Line 210 gives cancel on a sent event a 409. restart on a sent event is in neither list, and both lists are introduced with "i.e.", so it has no defined response.

To allow safely retrying requests, the homeserver will respond with success
if the target delayed event is already finalised with an outcome that matches the `action`, i.e.
if the `action` is `send` and the delayed event has already been sent,
or if the `action` is `cancel` and the delayed event has already been cancelled
(either due to user action or an error).
If the target delayed event is already finalised with an outcome that conflicts with the `action`, i.e.
if the `action` is `send` or `restart` and the delayed event has already been cancelled,
or if the `action` is `cancel` and the delayed event has already been sent,
the homeserver will respond with HTTP 409.

A periodic restart that lands after the timer, or another client's send, has already sent the event. 404 does not fit, which leaves each server to pick between 200 and 409, and the client reacts differently to each. matrix-js-sdk's membership manager recovers from a failed restart only on M_NOT_FOUND; a 409 falls through to a throw, and a 200 tells it the timer was reset after its membership is already gone.

https://github.com/matrix-org/matrix-js-sdk/blob/15ed5fe089394f54e52eb6a0aa21e1ac791230af/src/matrixrtc/MembershipManager.ts#L631-L643

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have included this in #4542.

Comment on lines +84 to +85
The homeserver MUST NOT send the event before the scheduled time, and
MAY send it up to 30 seconds after the scheduled send time.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
The homeserver MUST NOT send the event before the scheduled time, and
MAY send it up to 30 seconds after the scheduled send time.
The homeserver MUST NOT send the event before the scheduled time, except in response to the
[`send` action](#managing-scheduled-delayed-events), and MAY send it up to 30 seconds after the scheduled send time.

Line 84 forbids sending before the scheduled time without exception. Line 173 defines send as sending the event "immediately instead of waiting for its scheduled send time", so a server cannot both keep the MUST NOT and support the action.

The homeserver MUST NOT send the event before the scheduled time, and
MAY send it up to 30 seconds after the scheduled send time.

- `send` - Send the delayed event immediately instead of waiting for its scheduled send time.

The intent looks settled already: #4140 (comment), a thread about how late the timer may fire, where the promise being made was that the server never fires early on its own, and was committed in 1e527c3. The send action predates it by almost two years and keeps its own entry under Alternatives (line 551). Neither that thread nor the rewording in 062e649 mentions the action, so this reads as a wording slip rather than a decision.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-Client Server Client-Server API A-VOIP Any VoIP or MatrixRTC related proposals kind:feature MSC for not-core and not-maintenance stuff matrix-2.0 Required for Matrix 2.0 (note: do not rename - used in reports/links) proposal A matrix spec change proposal. Process state. spec-pr-missing MSC is accepted, but missing spec PR. Process state.

Projects

Status: Requires spec writing

Development

Successfully merging this pull request may close these issues.