mirror of
https://github.com/element-hq/synapse.git
synced 2024-11-22 09:35:45 +03:00
Fix deleting pushers when using sharded pushers. (#9465)
This commit is contained in:
parent
1b2d6d55c5
commit
66f4949e7f
10 changed files with 94 additions and 67 deletions
1
changelog.d/9465.bugfix
Normal file
1
changelog.d/9465.bugfix
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Fix deleting pushers when using sharded pushers.
|
|
@ -220,10 +220,6 @@ Asks the server for the current position of all streams.
|
||||||
|
|
||||||
Acknowledge receipt of some federation data
|
Acknowledge receipt of some federation data
|
||||||
|
|
||||||
#### REMOVE_PUSHER (C)
|
|
||||||
|
|
||||||
Inform the server a pusher should be removed
|
|
||||||
|
|
||||||
### REMOTE_SERVER_UP (S, C)
|
### REMOTE_SERVER_UP (S, C)
|
||||||
|
|
||||||
Inform other processes that a remote server may have come back online.
|
Inform other processes that a remote server may have come back online.
|
||||||
|
|
|
@ -645,9 +645,6 @@ class GenericWorkerServer(HomeServer):
|
||||||
|
|
||||||
self.get_tcp_replication().start_replication(self)
|
self.get_tcp_replication().start_replication(self)
|
||||||
|
|
||||||
async def remove_pusher(self, app_id, push_key, user_id):
|
|
||||||
self.get_tcp_replication().send_remove_pusher(app_id, push_key, user_id)
|
|
||||||
|
|
||||||
@cache_in_self
|
@cache_in_self
|
||||||
def get_replication_data_handler(self):
|
def get_replication_data_handler(self):
|
||||||
return GenericWorkerReplicationHandler(self)
|
return GenericWorkerReplicationHandler(self)
|
||||||
|
|
|
@ -74,6 +74,7 @@ class HttpPusher(Pusher):
|
||||||
self.timed_call = None
|
self.timed_call = None
|
||||||
self._is_processing = False
|
self._is_processing = False
|
||||||
self._group_unread_count_by_room = hs.config.push_group_unread_count_by_room
|
self._group_unread_count_by_room = hs.config.push_group_unread_count_by_room
|
||||||
|
self._pusherpool = hs.get_pusherpool()
|
||||||
|
|
||||||
self.data = pusher_config.data
|
self.data = pusher_config.data
|
||||||
if self.data is None:
|
if self.data is None:
|
||||||
|
@ -299,7 +300,7 @@ class HttpPusher(Pusher):
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
logger.info("Pushkey %s was rejected: removing", pk)
|
logger.info("Pushkey %s was rejected: removing", pk)
|
||||||
await self.hs.remove_pusher(self.app_id, pk, self.user_id)
|
await self._pusherpool.remove_pusher(self.app_id, pk, self.user_id)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
async def _build_notification_dict(
|
async def _build_notification_dict(
|
||||||
|
|
|
@ -25,6 +25,7 @@ from synapse.metrics.background_process_metrics import (
|
||||||
)
|
)
|
||||||
from synapse.push import Pusher, PusherConfig, PusherConfigException
|
from synapse.push import Pusher, PusherConfig, PusherConfigException
|
||||||
from synapse.push.pusher import PusherFactory
|
from synapse.push.pusher import PusherFactory
|
||||||
|
from synapse.replication.http.push import ReplicationRemovePusherRestServlet
|
||||||
from synapse.types import JsonDict, RoomStreamToken
|
from synapse.types import JsonDict, RoomStreamToken
|
||||||
from synapse.util.async_helpers import concurrently_execute
|
from synapse.util.async_helpers import concurrently_execute
|
||||||
|
|
||||||
|
@ -68,6 +69,13 @@ class PusherPool:
|
||||||
self._pusher_shard_config = hs.config.push.pusher_shard_config
|
self._pusher_shard_config = hs.config.push.pusher_shard_config
|
||||||
self._instance_name = hs.get_instance_name()
|
self._instance_name = hs.get_instance_name()
|
||||||
|
|
||||||
|
# We can only delete pushers on master.
|
||||||
|
self._remove_pusher_client = None
|
||||||
|
if hs.config.worker.worker_app:
|
||||||
|
self._remove_pusher_client = ReplicationRemovePusherRestServlet.make_client(
|
||||||
|
hs
|
||||||
|
)
|
||||||
|
|
||||||
# Record the last stream ID that we were poked about so we can get
|
# Record the last stream ID that we were poked about so we can get
|
||||||
# changes since then. We set this to the current max stream ID on
|
# changes since then. We set this to the current max stream ID on
|
||||||
# startup as every individual pusher will have checked for changes on
|
# startup as every individual pusher will have checked for changes on
|
||||||
|
@ -175,9 +183,6 @@ class PusherPool:
|
||||||
user_id: user to remove pushers for
|
user_id: user to remove pushers for
|
||||||
access_tokens: access token *ids* to remove pushers for
|
access_tokens: access token *ids* to remove pushers for
|
||||||
"""
|
"""
|
||||||
if not self._pusher_shard_config.should_handle(self._instance_name, user_id):
|
|
||||||
return
|
|
||||||
|
|
||||||
tokens = set(access_tokens)
|
tokens = set(access_tokens)
|
||||||
for p in await self.store.get_pushers_by_user_id(user_id):
|
for p in await self.store.get_pushers_by_user_id(user_id):
|
||||||
if p.access_token in tokens:
|
if p.access_token in tokens:
|
||||||
|
@ -380,6 +385,12 @@ class PusherPool:
|
||||||
|
|
||||||
synapse_pushers.labels(type(pusher).__name__, pusher.app_id).dec()
|
synapse_pushers.labels(type(pusher).__name__, pusher.app_id).dec()
|
||||||
|
|
||||||
await self.store.delete_pusher_by_app_id_pushkey_user_id(
|
# We can only delete pushers on master.
|
||||||
app_id, pushkey, user_id
|
if self._remove_pusher_client:
|
||||||
)
|
await self._remove_pusher_client(
|
||||||
|
app_id=app_id, pushkey=pushkey, user_id=user_id
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
await self.store.delete_pusher_by_app_id_pushkey_user_id(
|
||||||
|
app_id, pushkey, user_id
|
||||||
|
)
|
||||||
|
|
|
@ -21,6 +21,7 @@ from synapse.replication.http import (
|
||||||
login,
|
login,
|
||||||
membership,
|
membership,
|
||||||
presence,
|
presence,
|
||||||
|
push,
|
||||||
register,
|
register,
|
||||||
send_event,
|
send_event,
|
||||||
streams,
|
streams,
|
||||||
|
@ -42,6 +43,7 @@ class ReplicationRestResource(JsonResource):
|
||||||
membership.register_servlets(hs, self)
|
membership.register_servlets(hs, self)
|
||||||
streams.register_servlets(hs, self)
|
streams.register_servlets(hs, self)
|
||||||
account_data.register_servlets(hs, self)
|
account_data.register_servlets(hs, self)
|
||||||
|
push.register_servlets(hs, self)
|
||||||
|
|
||||||
# The following can't currently be instantiated on workers.
|
# The following can't currently be instantiated on workers.
|
||||||
if hs.config.worker.worker_app is None:
|
if hs.config.worker.worker_app is None:
|
||||||
|
|
72
synapse/replication/http/push.py
Normal file
72
synapse/replication/http/push.py
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Copyright 2021 The Matrix.org Foundation C.I.C.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
import logging
|
||||||
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
|
from synapse.http.servlet import parse_json_object_from_request
|
||||||
|
from synapse.replication.http._base import ReplicationEndpoint
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from synapse.server import HomeServer
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class ReplicationRemovePusherRestServlet(ReplicationEndpoint):
|
||||||
|
"""Deletes the given pusher.
|
||||||
|
|
||||||
|
Request format:
|
||||||
|
|
||||||
|
POST /_synapse/replication/remove_pusher/:user_id
|
||||||
|
|
||||||
|
{
|
||||||
|
"app_id": "<some_id>",
|
||||||
|
"pushkey": "<some_key>"
|
||||||
|
}
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
NAME = "add_user_account_data"
|
||||||
|
PATH_ARGS = ("user_id",)
|
||||||
|
CACHE = False
|
||||||
|
|
||||||
|
def __init__(self, hs: "HomeServer"):
|
||||||
|
super().__init__(hs)
|
||||||
|
|
||||||
|
self.pusher_pool = hs.get_pusherpool()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
async def _serialize_payload(app_id, pushkey, user_id):
|
||||||
|
payload = {
|
||||||
|
"app_id": app_id,
|
||||||
|
"pushkey": pushkey,
|
||||||
|
}
|
||||||
|
|
||||||
|
return payload
|
||||||
|
|
||||||
|
async def _handle_request(self, request, user_id):
|
||||||
|
content = parse_json_object_from_request(request)
|
||||||
|
|
||||||
|
app_id = content["app_id"]
|
||||||
|
pushkey = content["pushkey"]
|
||||||
|
|
||||||
|
await self.pusher_pool.remove_pusher(app_id, pushkey, user_id)
|
||||||
|
|
||||||
|
return 200, {}
|
||||||
|
|
||||||
|
|
||||||
|
def register_servlets(hs, http_server):
|
||||||
|
ReplicationRemovePusherRestServlet(hs).register(http_server)
|
|
@ -325,31 +325,6 @@ class FederationAckCommand(Command):
|
||||||
return "%s %s" % (self.instance_name, self.token)
|
return "%s %s" % (self.instance_name, self.token)
|
||||||
|
|
||||||
|
|
||||||
class RemovePusherCommand(Command):
|
|
||||||
"""Sent by the client to request the master remove the given pusher.
|
|
||||||
|
|
||||||
Format::
|
|
||||||
|
|
||||||
REMOVE_PUSHER <app_id> <push_key> <user_id>
|
|
||||||
"""
|
|
||||||
|
|
||||||
NAME = "REMOVE_PUSHER"
|
|
||||||
|
|
||||||
def __init__(self, app_id, push_key, user_id):
|
|
||||||
self.user_id = user_id
|
|
||||||
self.app_id = app_id
|
|
||||||
self.push_key = push_key
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def from_line(cls, line):
|
|
||||||
app_id, push_key, user_id = line.split(" ", 2)
|
|
||||||
|
|
||||||
return cls(app_id, push_key, user_id)
|
|
||||||
|
|
||||||
def to_line(self):
|
|
||||||
return " ".join((self.app_id, self.push_key, self.user_id))
|
|
||||||
|
|
||||||
|
|
||||||
class UserIpCommand(Command):
|
class UserIpCommand(Command):
|
||||||
"""Sent periodically when a worker sees activity from a client.
|
"""Sent periodically when a worker sees activity from a client.
|
||||||
|
|
||||||
|
@ -416,7 +391,6 @@ _COMMANDS = (
|
||||||
ReplicateCommand,
|
ReplicateCommand,
|
||||||
UserSyncCommand,
|
UserSyncCommand,
|
||||||
FederationAckCommand,
|
FederationAckCommand,
|
||||||
RemovePusherCommand,
|
|
||||||
UserIpCommand,
|
UserIpCommand,
|
||||||
RemoteServerUpCommand,
|
RemoteServerUpCommand,
|
||||||
ClearUserSyncsCommand,
|
ClearUserSyncsCommand,
|
||||||
|
@ -443,7 +417,6 @@ VALID_CLIENT_COMMANDS = (
|
||||||
UserSyncCommand.NAME,
|
UserSyncCommand.NAME,
|
||||||
ClearUserSyncsCommand.NAME,
|
ClearUserSyncsCommand.NAME,
|
||||||
FederationAckCommand.NAME,
|
FederationAckCommand.NAME,
|
||||||
RemovePusherCommand.NAME,
|
|
||||||
UserIpCommand.NAME,
|
UserIpCommand.NAME,
|
||||||
ErrorCommand.NAME,
|
ErrorCommand.NAME,
|
||||||
RemoteServerUpCommand.NAME,
|
RemoteServerUpCommand.NAME,
|
||||||
|
|
|
@ -44,7 +44,6 @@ from synapse.replication.tcp.commands import (
|
||||||
PositionCommand,
|
PositionCommand,
|
||||||
RdataCommand,
|
RdataCommand,
|
||||||
RemoteServerUpCommand,
|
RemoteServerUpCommand,
|
||||||
RemovePusherCommand,
|
|
||||||
ReplicateCommand,
|
ReplicateCommand,
|
||||||
UserIpCommand,
|
UserIpCommand,
|
||||||
UserSyncCommand,
|
UserSyncCommand,
|
||||||
|
@ -373,23 +372,6 @@ class ReplicationCommandHandler:
|
||||||
if self._federation_sender:
|
if self._federation_sender:
|
||||||
self._federation_sender.federation_ack(cmd.instance_name, cmd.token)
|
self._federation_sender.federation_ack(cmd.instance_name, cmd.token)
|
||||||
|
|
||||||
def on_REMOVE_PUSHER(
|
|
||||||
self, conn: AbstractConnection, cmd: RemovePusherCommand
|
|
||||||
) -> Optional[Awaitable[None]]:
|
|
||||||
remove_pusher_counter.inc()
|
|
||||||
|
|
||||||
if self._is_master:
|
|
||||||
return self._handle_remove_pusher(cmd)
|
|
||||||
else:
|
|
||||||
return None
|
|
||||||
|
|
||||||
async def _handle_remove_pusher(self, cmd: RemovePusherCommand):
|
|
||||||
await self._store.delete_pusher_by_app_id_pushkey_user_id(
|
|
||||||
app_id=cmd.app_id, pushkey=cmd.push_key, user_id=cmd.user_id
|
|
||||||
)
|
|
||||||
|
|
||||||
self._notifier.on_new_replication_data()
|
|
||||||
|
|
||||||
def on_USER_IP(
|
def on_USER_IP(
|
||||||
self, conn: AbstractConnection, cmd: UserIpCommand
|
self, conn: AbstractConnection, cmd: UserIpCommand
|
||||||
) -> Optional[Awaitable[None]]:
|
) -> Optional[Awaitable[None]]:
|
||||||
|
@ -684,11 +666,6 @@ class ReplicationCommandHandler:
|
||||||
UserSyncCommand(instance_id, user_id, is_syncing, last_sync_ms)
|
UserSyncCommand(instance_id, user_id, is_syncing, last_sync_ms)
|
||||||
)
|
)
|
||||||
|
|
||||||
def send_remove_pusher(self, app_id: str, push_key: str, user_id: str):
|
|
||||||
"""Poke the master to remove a pusher for a user"""
|
|
||||||
cmd = RemovePusherCommand(app_id, push_key, user_id)
|
|
||||||
self.send_command(cmd)
|
|
||||||
|
|
||||||
def send_user_ip(
|
def send_user_ip(
|
||||||
self,
|
self,
|
||||||
user_id: str,
|
user_id: str,
|
||||||
|
|
|
@ -758,9 +758,6 @@ class HomeServer(metaclass=abc.ABCMeta):
|
||||||
reconnect=True,
|
reconnect=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
async def remove_pusher(self, app_id: str, push_key: str, user_id: str):
|
|
||||||
return await self.get_pusherpool().remove_pusher(app_id, push_key, user_id)
|
|
||||||
|
|
||||||
def should_send_federation(self) -> bool:
|
def should_send_federation(self) -> bool:
|
||||||
"Should this server be sending federation traffic directly?"
|
"Should this server be sending federation traffic directly?"
|
||||||
return self.config.send_federation and (
|
return self.config.send_federation and (
|
||||||
|
|
Loading…
Reference in a new issue