Commit Graph
26011 Commits
Author SHA1 Message Date
Jason Robinson 48b45263fa Merge remote-tracking branch 'origin/develop' into anoa/msc4429 2026-07-10 15:15:48 +03:00
c16dbe7dbc Apply suggestions from code review
Co-authored-by: Andrew Morgan <1342360+anoadragon453@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-07-10 15:13:18 +03:00
Jason Robinson 30c5602cc4 Rewrite ProfileUpdateAction docstring 2026-07-10 15:05:20 +03:00
Jason Robinson 72e3d2363a Linkify MSC4429 in the docs 2026-07-10 15:02:23 +03:00
Jason Robinson b3237ce97f Fix config schema 2026-07-10 15:00:52 +03:00
18978f02e5 Apply suggestions from code review
Co-authored-by: Andrew Morgan <1342360+anoadragon453@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-07-10 14:57:37 +03:00
Erik Johnston 87439e55b5 Fix storage type mismatches where values didn't match their column types (#19911)
A handful of places in the storage layer bound a value whose Python type
didn't match the declared column type — an `int` into a `TEXT` column,
or a `str` into a `BIGINT` column — and relied on psycopg2's loose
coercion to paper over the mismatch. These are latent correctness bugs:
they only work because the driver silently converts, and a stricter
driver that binds typed parameters rejects them outright.

Found during a Rust port of the database pool where the driver does not
coerce automatically.

Each fix binds the value with the type the column actually declares,
rather than depending on driver-specific coercion. All changes are
behaviour-preserving on psycopg2 and sqlite.

There is also a fix to the multi-writer id-gen tests where we forgot to
commit. This is tangential, but was found during the same effort.

  ### Changes

- **`device_lists_remote_extremeties.stream_id (TEXT)`** —
`_update_remote_device_list_cache_txn` (typed `stream_id: int`) bound an
int; store it as a string, matching the column and the sibling
`_update_remote_device_list_cache_entry_txn` (typed `stream_id: str`).
The old mismatch, when rejected, was swallowed inside the device-list
resync and hung `query_devices`.
- **`user_filters.filter_id (BIGINT)`** — `get_user_filter` bound the
raw `int | str` (a string, from sync requests). It already validates via
`int(filter_id)`; bind that int so it matches the column.
- **`rejections.last_check (TEXT)`** — both writers stored
`clock.time_msec()` (an int); store the timestamp as a string.
- **user-directory temp position** — the `populate_user_directory`
background update's staging column
`_temp_populate_user_directory_position.position` was `TEXT` but held an
int (read back into a `BIGINT` column). Declare it `BIGINT`. The temp
table is created and dropped within the background update, so there's no
migration.

- **`test_batched_state_group_storing`** — selected from
`state_group_edges` with a stringified `state_group`; bind the int
directly (the column is an integer).
- **Multi-writer id-generator tests** — constructing a
`MultiWriterIdGenerator` prunes stale `stream_positions` rows, but the
harness never committed, so the cleanup only survived because adbapi
keeps one connection per thread with its transaction open. Commit after
construction so it persists regardless of pool semantics (the delete is
legitimate work that should be committed anyway).
2026-07-10 10:38:43 +01:00
Erik JohnstonandClaude Opus 4.8 9bbd974b3e Add index to sliding_sync_connection_lazy_members on connection_position (#19923)
This speeds up the cascading delete from
`sliding_sync_connection_positions`, which without an index on
`connection_position` requires a sequential scan of the whole table for
each deleted position.

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-10 10:37:38 +01:00
Erik JohnstonandClaude Fable 5 3f3edaf029 Make the presence state-machine timers configurable (#19942)
Adds `last_active_granularity`, `sync_online_timeout` and `idle_timeout`
options to the `presence` config section, controlling the previously
hard-coded `LAST_ACTIVE_GRANULARITY`, `SYNC_ONLINE_TIMEOUT` and
`IDLE_TIMER` constants (which remain as the defaults).

This is mainly useful on deployments that ratelimit how often syncs can
affect presence (`rc_presence`): the sync timeout must exceed the
ratelimit interval or users flap offline between syncs, so tuning down
presence traffic currently requires squeezing under the fixed 30s limit.

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-09 17:21:50 +01:00
Eric Eastwood 365df86536 Fix Complement test flake when restarting Synapse workers (cross-test pollution caused by nginx upstreams being temporarily unavailable) (#19936)
Fix https://github.com/element-hq/synapse/issues/19907

The flake manifested as a failure pointing at
`TestMessagesOverFederation/Backfill_from_nearby_backward_extremities_past_token`
but was actually caused by some cross-test pollution from an earlier
test (`TestOIDCProviderUnavailable`) causing some workers to be
temporarily unavailable.

As explained in
https://github.com/element-hq/synapse/issues/19907#issuecomment-4917362461,

> ### Cross-test pollution
> 
> When I point an LLM at the logs, it points to
`TestOIDCProviderUnavailable` being the culprit because of the server
restarts polluting this test. When this flake happens, we can indeed see
that `TestOIDCProviderUnavailable` runs before
`TestMessagesOverFederation`.
> 
> ```
> PASS TestEventBetweenMakeJoinAndSendJoinIsNotLost 15.08s
> PASS TestFederation/parallel/HS2_->_HS1 1.5s
> PASS TestFederation/parallel/HS1_->_HS2 1.51s
> PASS TestFederation/parallel 0s
> PASS TestFederation 15.12s
> PASS TestOIDCProviderUnavailable//login/sso/redirect_shows_HTML_error
0.02s
> PASS TestOIDCProviderUnavailable 8.62s
> FAIL
TestMessagesOverFederation/Backfill_from_nearby_backward_extremities_past_token
0.89s
> FAIL TestMessagesOverFederation 1.1s
> PASS TestSynapseVersion/Synapse_version_matches_current_git_checkout
0.97s
> PASS TestSynapseVersion 0.97s
> ```
> 
> The pollution happens because we enable
[`COMPLEMENT_ENABLE_DIRTY_RUNS`](https://github.com/element-hq/synapse/blob/c63d77a79d7157f26f849684520ba9e99f4d07c0/scripts-dev/complement.sh#L309-L311)
([docs](https://github.com/matrix-org/complement/blob/0e6f8552ff0c99fddb97222399efed3e1f0cb91a/ENVIRONMENT.md#complement_enable_dirty_runs))
which means Complement will reuse deployments (shares homeservers
between tests).
> 
> During the `TestOIDCProviderUnavailable` test, there are some stray
federation requests that hit the homeserver while it's still booting
which marks the nginx upstream as unavailable for 10 seconds. nginx has
a default of
[`max_fails=1`](https://nginx.org/en/docs/http/ngx_http_upstream_module.html#max_fails)
and
[`fail_timeout=10s`](https://nginx.org/en/docs/http/ngx_http_upstream_module.html#fail_timeout).
Then when `TestMessagesOverFederation` starts, we're still in the 10
second unavailable window and nginx doesn't even try to connect at all.
> 
> <details>
> <summary>LLM summary of the logs and how this happens in
practice</summary>
> 
> 1. **19:52:10–11** — the previous federation test finishes:
`user-3:hs2` does a faster-join (`send_join?omit_members=true`) to
`!YnyCRpCLIpimppIreR:hs1`, so `hs2` kicks off a
`sync_partial_state_room` background resync that is still running when
the test ends.
> 2. **19:52:11.6** — `TestOIDCProviderUnavailable` starts and calls
`deployment.StopServer(t, "hs1")` / `StartServer`
(`complement/tests/oidc_test.go:78-80`) to apply an OIDC config
fragment. `hs1` gets `SIGTERM`; new supervisord at 19:52:13.3. `hs2` is
not restarted and keeps retrying its unfinished work.
> 3. **19:52:14** — `hs1`'s nginx is up, but the Synapse workers aren't:
`federation_inbound` only listens on `18015` at 19:52:18.7,
`federation_reader` on `18016` at 19:52:19.0.
> 4. **19:52:15–16** — `hs2`'s retries arrive in that gap: `PUT
/_matrix/federation/v1/send/…` → `18015` refused; `GET
/state_ids/!YnyCRpCLIpimppIreR:hs1` → `18016` refused. With nginx
defaults (`max_fails=1`, `fail_timeout=10s`) and only one server per
upstream block, both upstreams are now marked down until ~19:52:25/26.
(Side casualty: `hs2`'s partial-state resync gives up — "We can't get
valid state history" — and puts `hs1` on a 10-minute federation
backoff.)
> 5. **19:52:21.5** — the failing test's `make_join` for
`@user-5-bob:hs2` reaches `hs1`'s nginx → `no live upstreams` → `502` →
the join fails, even though the worker has been listening for 2.5
seconds by then.
> 6. **19:52:22** — `TestSynapseVersion`'s `GET
/_matrix/federation/v1/version` hits the same dead upstream → `502` → it
fails too.
> 
> So it's a flake caused by a race between the OIDC test's container
restart, hs2's background federation retries, and nginx's passive
health-check — not anything wrong with the backfill logic under test.
> 
> </details>
> 
> 
> We can indeed confirm this suspicion with these logs
> 
> 
https://github.com/element-hq/synapse/actions/runs/28888070856/job/85701936736
(archive:
[85701936736.log](https://github.com/user-attachments/files/29809986/85701936736.log)):
> ```
> Error: 2026/07/07 19:52:20 [error] 34#34: *1 no live upstreams while
connecting to upstream, client: 172.18.0.3, server: localhost, request:
"PUT /_matrix/federation/v1/send/1783453927718 HTTP/1.1", upstream:
"http://federation_inbound/_matrix/federation/v1/send/1783453927718",
host: "hs1"
> ...
> 
> Error: 2026/07/07 19:52:21 [error] 33#33: *4 no live upstreams while
connecting to upstream, client: 172.18.0.3, server: localhost, request:
"GET
/_matrix/federation/v1/make_join/%21scAbyTQDdaauGYicpU%3Ahs1/%40user-5-bob%3Ahs2?ver=1&ver=2&ver=3&ver=4&ver=5&ver=6&ver=7&ver=8&ver=9&ver=10&ver=11&ver=12&ver=org.matrix.msc3757.10&ver=org.matrix.msc3757.11&ver=org.matrix.hydra.11
HTTP/1.1", upstream:
"http://federation_reader/_matrix/federation/v1/make_join/%21scAbyTQDdaauGYicpU%3Ahs1/%40user-5-bob%3Ahs2?ver=1&ver=2&ver=3&ver=4&ver=5&ver=6&ver=7&ver=8&ver=9&ver=10&ver=11&ver=12&ver=org.matrix.msc3757.10&ver=org.matrix.msc3757.11&ver=org.matrix.hydra.11",
host: "hs1"
> ```
> 
> The fix here would be to disable nginx's unavailable upstream behavior
by configuring `max_fails=0` in the upstream block:
https://github.com/element-hq/synapse/blob/c63d77a79d7157f26f849684520ba9e99f4d07c0/docker/configure_workers_and_start.py#L374-L378
2026-07-09 11:12:28 -05:00
Eric Eastwood 9c6cca1ac9 Add clean deploy FIXME note for TestOIDCProviderUnavailable (#19938)
Tracked by https://github.com/element-hq/synapse/issues/19937
2026-07-09 11:09:59 -05:00
Erik JohnstonandClaude Fable 5 b4deb24be6 Use a CPU-time budget for test_lock_contention to fix postgres flakiness (#19929)
`test_lock_contention` is a performance-regression canary (#16840): the
pathological behaviour it guards against spent ~30s spinning the CPU, vs
~0.5s when healthy. The 5s wall-clock alarm it used was calibrated on
SQLite, but against PostgreSQL a healthy run already takes 3-4s of
wall-clock time (500 sequential acquire/release cycles, each a real
database round-trip), so any CI load pushed it over the limit.

Add a `cpu_time` mode to `tests/utils.py`'s test_timeout, implemented
with
[`setitimer(ITIMER_PROF)`](https://docs.python.org/3/library/signal.html#signal.setitimer),
which budgets process CPU time instead of wall-clock time. Time spent
blocked on the database or lost to a loaded CI runner no longer counts,
while a regression to CPU-spinning still trips the alarm mid-spin. A
healthy run costs <1s of CPU on either database engine; the budget is
10s.

This also subsumes the RISC-V wall-clock carve-out from #18430, which is
removed.

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-09 10:40:53 +01:00
Jason Robinson 8e75e7b21d Always enable profile replication endpoints
Since we moved a lot of stuff to happen in the profile update stream writers, we need to always have the replication endpoints enabled now.
2026-07-08 17:16:47 +03:00
Jason Robinson fcac74620f Rename profile updates db deltas as we got new stuff from develop 2026-07-08 15:16:00 +03:00
Jason Robinson 50527b1f2a Hopefully final fix to deactivate over replication
Replication path arguments need to be strings.
2026-07-08 15:15:40 +03:00
Jason Robinson 3ed759a32f Add include_profile_updates_in_sync to the config schema 2026-07-08 13:01:16 +03:00
Jason Robinson e9b8fd786b Fix deactivation from a worker that is not profile writer
Thanks sytest 🤩
2026-07-08 11:51:00 +03:00
Jason Robinson cb322e497f Ensure our own syncing user always gets their updates, even if they're not in any rooms 2026-07-08 11:45:41 +03:00
Jason Robinson 2ed4201dbc Adjust a few new tests after merging from develop 2026-07-07 22:52:55 +03:00
Jason Robinson 3180924c5a Update Rust side versions endpoint
Since https://github.com/element-hq/synapse/commit/c63d77a79d7157f26f849684520ba9e99f4d07c0 moved things
2026-07-07 22:48:34 +03:00
Jason Robinson cb81bd3a6b Merge remote-tracking branch 'origin/develop' into anoa/msc4429
# Conflicts:
#	synapse/rest/client/versions.py
2026-07-07 22:29:35 +03:00
Jason Robinson ef9d99515a Dispatch deletion of profile upon deactivation over replication to the right instance, if necessary 2026-07-07 22:19:05 +03:00
Jason Robinson ae4e686f6f Ensure delete_profile_upon_deactivation does profile deletion and profile updates stream updates in a single transaction 2026-07-07 22:06:10 +03:00
Jason Robinson 739824217e Refactor user left room / user joined room profile updates
We now do all the actions relating to the stream updates in one transaction.

Additionally ensure we wake up the notifier for the users concerned.
2026-07-07 21:20:27 +03:00
Eric Eastwood c63d77a79d Rust database access via Python database connection pool v2 (#19878)
This is a stepping stone before we can go full Rust everywhere. We're
providing a generic interface as we want database access to work in
Synapse and `synapse-rust-apps`. In `synapse-rust-apps`, we will use a
`tokio-postgres` based database connection pool so it's full Rust.

We want to avoid the situation where we have two database connection
pools (one for Python, one for Rust) as we've run into connection
exhaustion problems on Matrix.org before.

As an example of using it and sanity check for all this work (including
tests), I've also ported over the `/versions` handler to the Rust side
with database access. The `/versions` endpoint is the simplest endpoint
I could find that still had some database access. Hopefully the refactor
on `/versions` isn't that controversial as it's not really the point of
this PR. We can always remove it from this PR but it's just here as a
sanity check that all of this works.


### Why `runInteraction(...)`?

Using the same `runInteraction` pattern that we already have in Synapse
means we can port over existing Synapse code/endpoints without much
thought. But this pattern also makes sense because we want[^1]
transactions to have repeatable-read isolation (easy to think about,
less foot-guns). Having everything thappen in a function callback means
we can do retries for serialization/deadlock errors.

[^1]: To note: Ideally, we'd want the least isolation possible but the
problem is that there is no tooling to yell at you when your
queries/logic is wrong so repeatable-read isolation is a great balance.


> When an application receives this error message, it should abort the
current transaction and retry the whole transaction from the beginning.
The second time through, the transaction will see the
previously-committed change as part of its initial view of the database,
so there is no logical conflict in using the new version of the row as
the starting point for the new transaction's update.
> 
> Note that only updating transactions might need to be retried;
read-only transactions will never have serialization conflicts.
>
> *--
https://www.postgresql.org/docs/current/transaction-iso.html#XACT-REPEATABLE-READ*


As a note, this strategy is less of an impedance mismatch (aligns more
closely) with Synapse so the glue code for the `python_db_pool` should
also be simpler.


### How does this interact with logcontext (`LoggingContext`)?

See [docs on log
contexts](https://github.com/element-hq/synapse/blob/4e9f7757f17ba81b8747b7f8f9646d17df145aa3/docs/log_contexts.md)
for more background.

We already support normal logging from Rust -> Python with `pyo3-log`
and `log` but as soon as we pass a thread boundary, everything is logged
against the `sentinel` log context. Normally, we want logs and CPU/DB
usage correlated with the request that spawned the work.

You can see how I took a stab at fixing this in
https://github.com/element-hq/synapse/pull/19846 by capturing the
logcontext in a Tokio task local and re-activating as necessary. For
example, in that PR, I reactivated the logcontext in
`run_python_awaitable(...)` which we use to call `runInteraction(...)`
from the Rust side which means all of the database usage is correlated
with the request as expected. It also means any `log:info!(...)` done in
`run_interaction(...)` is correlated correctly. But there needs to be a
better story for when you want to log everywhere else.

I haven't explored tracking CPU usage on the Rust side.

I've left all of this out of this PR as I think it will be better to
tackle this as a dedicated follow-up. For example, I'm thinking about
instead creating a new `LoggingContext` with the `parent_context` set to
the calling context and try to avoid needing to call
`set_current_context(...)` on the Python side where possible (like
tracking CPU).



### Testing strategy

Added some tests that exercise some `async` Rust handlers for the
`/versions` endpoint:
```
SYNAPSE_TEST_LOG_LEVEL=INFO poetry run trial tests.rest.client.test_versions.VersionsTestCase
```

Real-world:

 1. `poetry run synapse_homeserver --config-path homeserver.yaml`
 1. `GET http://localhost:8008/_matrix/client/versions`
2026-07-07 13:07:35 -05:00
Jason Robinson d7e0d353ff Add some notes on missing tests for future readers
I changed things so deactivation did call these and no tests failed.
2026-07-07 19:18:23 +03:00
Jason Robinson d0aa8d00fc Revert "Make delete_profile_upon_deactivation first delete the profile fields, to update the profile updates stream"
This reverts commit 1937e764ad.
2026-07-07 19:14:04 +03:00
Jason Robinson 905226577f Remove a few unused methods and fix docstrings 2026-07-07 19:13:50 +03:00
Jason Robinson 1937e764ad Make delete_profile_upon_deactivation first delete the profile fields, to update the profile updates stream 2026-07-07 19:06:52 +03:00
Jason Robinson f7d05558b6 Refactor profile updates behind the profile updates stream writer
Setting a profile field (including displayname / avatar_uri) now needs to happen on a profile updates stream writer. There are new "dispatch" methods to do the profile field set/delete, that handle pushing the update over replication, if required.

Profile field updates and profile updates stream writes are now in the same database transaction.
2026-07-07 18:50:59 +03:00
Olivier 'reivilibre ec6c53e7df Merge branch 'master' into develop 2026-07-07 15:01:22 +01:00
Olivier 'reivilibre be8d900438 1.156.0 v1.156.0 2026-07-07 14:20:45 +01:00
Erik JohnstonandClaude Fable 5 f8fefb09bd Re-expose the standalone format_event_* transforms for backwards compat (#19922)
The port of event serialization to Rust (#19837) removed
`format_event_raw`, `format_event_for_client_v1`,
`format_event_for_client_v2` and
`format_event_for_client_v2_without_room_id` from
`synapse.events.utils`, but there are modules in the wild that import
them from there.

Reimplement them as standalone pyfunctions in Rust, operating directly
on the Python dict so the original semantics are preserved exactly
(in-place mutation, returning the same dict, arbitrary non-JSON values
passing through, KeyError on a missing `unsigned` in the v1 format), and
re-export them from `synapse.events.utils`.

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-07 13:47:03 +01:00
27c3b5394b Port the synchronous event serialization core to Rust (#19837)
### Summary

This moves the synchronous core of client event serialization out of
`synapse/events/utils.py` and into Rust
(`rust/src/events/serialize.rs`).

Event serialization is on the hot path for `/sync`, `/messages`, and
most client-facing endpoints. Previously it was a recursive pure-Python
routine (`_serialize_event` / `_inject_bundled_aggregations` /
`only_fields`) that interleaved
CPU-bound formatting with `async` DB/IO. This PR separates those two
concerns and moves the CPU-bound half to Rust:

- **Async prep stays in Python.**
`EventClientSerializer._prepare_serialization` does all DB/IO up front:
batch-fetching redaction events and running the registered module
`unsigned`-callback hooks, for the top-level events *and* every bundled
sub-event (edits and thread latest events, which are themselves
serialized). The admin/MSC4354 config is resolved once via
`_update_config`, rather than re-checked on every recursive call as the
old code did.
- **The synchronous core moves to Rust.** Given an event plus the
pre-fetched `redaction_map`, `unsigned_additions`, and
`bundle_aggregations`, the Rust code produces the client JSON entirely
in Rust — including the v1/v2 format transforms, `only_event_fields`
filtering, redaction handling, and recursive bundled aggregations.

### Details

- The Rust entry point is a single batch function, `serialize_events`,
taking a list of `(event, membership)` pairs. The three lookup maps are
shared across the whole batch, so they're read out of Python and
converted to Rust
structures **once** per batch rather than once per event.
`EventClientSerializer.serialize_event` (singular) is a thin wrapper
that calls it with a one-element list.
- `SerializeEventConfig` is now a Rust `pyclass`, and the old
`event_format` callable is replaced by the `EventFormat` enum (`Raw` /
`ClientV1` / `ClientV2` / `ClientV2WithoutRoomId`). Call sites in
`rest/admin/events.py` and
`rest/client/{notifications,room,sync}.py` are updated to pass the enum.
`make_config_for_admin` and MSC4354 enablement now go through
`SerializeEventConfig.for_admin()` / `with_msc4354()`.
- New accessors on `EventInternalMetadata` (`redacted_by`, `txn_id`,
`device_id`, `token_id`, `delay_id`, `soft_failed`,
`policy_server_spammy`) expose to Rust the fields the serializer reads.
- The `_split_field` unit tests move from `tests/events/test_utils.py`
to a Rust test in `serialize.rs`, since the implementation moved.

### Behaviour

This is intended to be a behaviour-preserving refactor — the Rust core
mirrors the previous Python output (field ordering, v1 key promotion,
redaction placement per room version, null-`redacts` handling,
transaction-ID gating).

Existing serialization, relations, and sync tests pass unchanged.

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Eric Eastwood <madlittlemods@gmail.com>
Co-authored-by: Eric Eastwood <erice@element.io>
2026-07-07 11:59:27 +01:00
Eric Eastwood 026937b251 Update FakeChannel.await_result(...) to drive async Rust (Tokio runtime/thread pool) (#19879)
Split off from https://github.com/element-hq/synapse/pull/19878 (needed
to drive requests in tests that use async Rust)

Follow-up to https://github.com/element-hq/synapse/pull/19871
2026-07-07 04:07:19 -05:00
Andrew Morgan aa0dbdc1cd Update check_schema_delta.py to better parse raw SQL schema deltas 2026-07-07 10:02:28 +03:00
Jason Robinson 2bea8c0657 Revert "Add a prune job for the profile updates stream tables"
Extracted to a follow-up pr.

This reverts commit b657d2f8
2026-07-07 10:01:24 +03:00
Jason Robinson 15466d2621 Use sha256 instead of md5
To make CI happier, even though we just want to compare content has changed.
2026-07-06 18:42:38 +03:00
Jason Robinson 10cccac913 Ensure we bust the lazy loading cache for profile updates, when field values change 2026-07-06 18:36:57 +03:00
Jason Robinson 73986ef24b Add docstring to get_lazy_loaded_profile_fields_cache 2026-07-06 16:41:49 +03:00
Jason Robinson ac1bdfba17 Clarify clear_profile_updates_for_user docstring 2026-07-06 16:39:00 +03:00
Lukas JungandAndrew Morgan 963e486a70 Recreate user profile on account reactivation (#19902)
Co-authored-by: Andrew Morgan <1342360+anoadragon453@users.noreply.github.com>
2026-07-06 12:38:24 +00:00
Jason Robinson f431951fdb Add a test to ensure display name changes don't generate extra room_joined profile updates rows, due to membership event changes 2026-07-06 15:23:11 +03:00
Jason Robinson b571fcef4e Clear all old ProfileUpdate rows from profile_updates_per_user on a leave
Regardless of action. This is cleaner and also ensures a join/leave/join/leave case might not get confused.
2026-07-06 15:08:10 +03:00
Erik JohnstonandClaude Opus 4.8 5f89ff2b31 Add an index on sliding_sync_connections.last_used_ts (#19912)
Speeds up finding and deleting expired sliding sync connections in
`delete_old_sliding_sync_connections`, which previously required a
sequential scan.

On matrix.org I have a suspicion that this might end up blocking some
SSS connections during the delete, which can take minutes. Specifically,
I think the deletion blocks this delete:


https://github.com/element-hq/synapse/blob/ff19c034d300869e64878a15aed9a97f1cec59e4/synapse/storage/databases/main/sliding_sync.py#L233-L241

We didn't previously have an index because we wanted the postgres HOT
updates, however we also limit the update frequency to once every 5
minutes, so hopefully this is fine.

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 12:59:11 +01:00
Jason Robinson 425aa00a9b Add a join → leave → re-join → leave to try and rule out bugs in that aspect 2026-07-06 14:50:04 +03:00
Andrew Morgan c7a47bc121 Fix flaky 3PID inhibit error unit tests (#19913) 2026-07-06 11:34:41 +00:00
dependabot[bot] ff19c034d3 Bump golang.org/x/net from 0.52.0 to 0.55.0 in /complement (#19910)
Signed-off-by: dependabot[bot] <support@github.com>
2026-07-06 09:08:27 +00:00
Jason Robinson 1955fbee22 Ensure falsey values survive the set_field / sync profile updates -cycle 2026-07-03 18:28:49 +03:00
807795e5ee Change the MSC3814 dehydrated device /events endpoint paging to match spec conventions (#19897)
To match [the spec requirements for
pagination](https://spec.matrix.org/v1.9/appendices/#pagination):

* rename the query parameter of
`/org.matrix.msc3814.v1/dehydrated_device/[device_id]/events` to `from`,
and
* omit `next_batch` from the response content if there are no more
events to fetch

This matches [the changes that are coming in
MSC3814](https://github.com/matrix-org/matrix-spec-proposals/pull/3814/files#r1540896531).

The previous change https://github.com/element-hq/synapse/pull/19896
kept the old POST API to support old clients. This preserves that
compatibility, so the POST API still works how it used to.

Depends on https://github.com/element-hq/synapse/pull/19896
Part of https://github.com/element-hq/element-meta/issues/2799


### Pull Request Checklist

* [x] Pull request is based on the develop branch
* [x] Pull request includes a [changelog
file](https://element-hq.github.io/synapse/latest/development/contributing_guide.html#changelog).
The entry should:
* [x] [Code
style](https://element-hq.github.io/synapse/latest/code_style.html) is
correct (run the
[linters](https://element-hq.github.io/synapse/latest/development/contributing_guide.html#run-the-linters))

---------

Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>
Co-authored-by: Quentin Gliech <quenting@element.io>
2026-07-03 14:48:43 +02:00