Skip to content
This repository has been archived by the owner on Apr 26, 2024. It is now read-only.

Several write operations still occur on the main process when /register is routed to workers #13379

Open
anoadragon453 opened this issue Jul 25, 2022 · 1 comment
Labels
A-Registration Creating an account A-Workers Problems related to running Synapse in Worker Mode (or replication) T-Enhancement New features, changes in functionality, improvements in performance, or user-facing enhancements.

Comments

@anoadragon453
Copy link
Member

It's possible to route POST /_matrix/client/v3/register to workers. This allows offloading most of the work involved in registration to the main process. A few operations occur on the main process (here is where the logic splits between worker and main process):

def _register_user(
self,
txn: LoggingTransaction,
user_id: str,
password_hash: Optional[str],
was_guest: bool,
make_guest: bool,
appservice_id: Optional[str],
create_profile_with_displayname: Optional[str],
admin: bool,
user_type: Optional[str],
shadow_banned: bool,
) -> None:
user_id_obj = UserID.from_string(user_id)
now = int(self._clock.time())
try:
if was_guest:
# Ensure that the guest user actually exists
# ``allow_none=False`` makes this raise an exception
# if the row isn't in the database.
self.db_pool.simple_select_one_txn(
txn,
"users",
keyvalues={"name": user_id, "is_guest": 1},
retcols=("name",),
allow_none=False,
)
self.db_pool.simple_update_one_txn(
txn,
"users",
keyvalues={"name": user_id, "is_guest": 1},
updatevalues={
"password_hash": password_hash,
"upgrade_ts": now,
"is_guest": 1 if make_guest else 0,
"appservice_id": appservice_id,
"admin": 1 if admin else 0,
"user_type": user_type,
"shadow_banned": shadow_banned,
},
)
else:
self.db_pool.simple_insert_txn(
txn,
"users",
values={
"name": user_id,
"password_hash": password_hash,
"creation_ts": now,
"is_guest": 1 if make_guest else 0,
"appservice_id": appservice_id,
"admin": 1 if admin else 0,
"user_type": user_type,
"shadow_banned": shadow_banned,
},
)
except self.database_engine.module.IntegrityError:
raise StoreError(400, "User ID already taken.", errcode=Codes.USER_IN_USE)
if self._account_validity_enabled:
self.set_expiration_date_for_user_txn(txn, user_id)
if create_profile_with_displayname:
# set a default displayname serverside to avoid ugly race
# between auto-joins and clients trying to set displaynames
#
# *obviously* the 'profiles' table uses localpart for user_id
# while everything else uses the full mxid.
txn.execute(
"INSERT INTO profiles(user_id, displayname) VALUES (?,?)",
(user_id_obj.localpart, create_profile_with_displayname),
)
if self.hs.config.stats.stats_enabled:
# we create a new completed user statistics row
# we don't strictly need current_token since this user really can't
# have any state deltas before now (as it is a new user), but still,
# we include it for completeness.
current_token = self._get_max_stream_id_in_current_state_deltas_txn(txn)
self._update_stats_delta_txn(
txn, now, "user", user_id, {}, complete_with_stream_id=current_token
)
self._invalidate_cache_and_stream(txn, self.get_user_by_id, (user_id,))

I think the only operation in this method that can't currently be completed by a worker is:

current_token = self._get_max_stream_id_in_current_state_deltas_txn(txn)
self._update_stats_delta_txn(
txn, now, "user", user_id, {}, complete_with_stream_id=current_token
)

But the rest could potentially be delegated to the worker process.

I don't believe that these operations are particularly resource intensive.

@anoadragon453 anoadragon453 added A-Workers Problems related to running Synapse in Worker Mode (or replication) T-Enhancement New features, changes in functionality, improvements in performance, or user-facing enhancements. A-Registration Creating an account labels Jul 25, 2022
@Fizzadar
Copy link
Contributor

Fizzadar commented Aug 2, 2023

We've been looking at implementing this - although I think this might be possible wiouth much change; specifically you reference _update_stats_delta_txn as the method that can't be run on workers but I don't think that's the case - following the code it seems to only make an upsert into user_stats_current for the new user. I'm not seeing any main-specific code or restrictions, am I missing something here?

The remainder of the _register_user transaction also seems safe to run on a worker, if the above is true this may just be a case of removing the replicated call!

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
A-Registration Creating an account A-Workers Problems related to running Synapse in Worker Mode (or replication) T-Enhancement New features, changes in functionality, improvements in performance, or user-facing enhancements.
Projects
None yet
Development

No branches or pull requests

2 participants