-
-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Don't wake up destination transaction queue if they're not due for retry. #16223
Changes from 10 commits
ff14b77
87ac2ed
99d6e1c
badce67
0b68944
f2149dc
9456f06
55c641e
448e7d9
89c329e
932cc3e
cb2295f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
Improve resource usage when sending data to a large number of remote hosts that are marked as "down". | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This seems to add the filtering to
Are there other EDUs we should worry about here? (Typing? Device list stuff? to-device messages?) What about the other methods on FederationSender?
is the point that only the former three handle multiple destinations in one call? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. (Oh there is logic below for typing EDUs. But why don't they go via the federation sender too?) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh, mainly because a) |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -14,7 +14,7 @@ | |
|
||
import logging | ||
from enum import Enum | ||
from typing import TYPE_CHECKING, Iterable, List, Optional, Tuple, cast | ||
from typing import TYPE_CHECKING, Dict, Iterable, List, Optional, Tuple, cast | ||
|
||
import attr | ||
from canonicaljson import encode_canonical_json | ||
|
@@ -28,8 +28,8 @@ | |
LoggingTransaction, | ||
) | ||
from synapse.storage.databases.main.cache import CacheInvalidationWorkerStore | ||
from synapse.types import JsonDict | ||
from synapse.util.caches.descriptors import cached | ||
from synapse.types import JsonDict, StrCollection | ||
from synapse.util.caches.descriptors import cached, cachedList | ||
|
||
if TYPE_CHECKING: | ||
from synapse.server import HomeServer | ||
|
@@ -205,6 +205,26 @@ def _get_destination_retry_timings( | |
else: | ||
return None | ||
|
||
@cachedList( | ||
cached_method_name="get_destination_retry_timings", list_name="destinations" | ||
) | ||
async def get_destination_retry_timings_batch( | ||
self, destinations: StrCollection | ||
) -> Dict[str, Optional[DestinationRetryTimings]]: | ||
rows = await self.db_pool.simple_select_many_batch( | ||
table="destinations", | ||
iterable=destinations, | ||
column="destination", | ||
retcols=("destination", "failure_ts", "retry_last_ts", "retry_interval"), | ||
desc="get_destination_retry_timings_batch", | ||
) | ||
|
||
return { | ||
row.pop("destination"): DestinationRetryTimings(**row) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I guess it's critical here that the key (and hence the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, it is a little hacky. I can update it to actually specify each key explicitly? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it's fine, it just took me a moment to see what was going on. (And: it's the kind of thing that I'm paranoid might break in a future Python release) |
||
for row in rows | ||
if row["retry_last_ts"] and row["failure_ts"] and row["retry_interval"] | ||
} | ||
|
||
async def set_destination_retry_timings( | ||
self, | ||
destination: str, | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -19,6 +19,7 @@ | |
from synapse.api.errors import CodeMessageException | ||
from synapse.metrics.background_process_metrics import run_as_background_process | ||
from synapse.storage import DataStore | ||
from synapse.types import StrCollection | ||
from synapse.util import Clock | ||
|
||
if TYPE_CHECKING: | ||
|
@@ -116,6 +117,30 @@ async def get_retry_limiter( | |
) | ||
|
||
|
||
async def filter_destinations_by_retry_limiter( | ||
destinations: StrCollection, | ||
clock: Clock, | ||
store: DataStore, | ||
retry_due_within_ms: int = 0, | ||
) -> StrCollection: | ||
"""Filter down the list of destinations to only those that will are either | ||
alive or due for a retry (within `retry_due_within_ms`) | ||
""" | ||
if not destinations: | ||
return destinations | ||
|
||
retry_timings = await store.get_destination_retry_timings_batch(destinations) | ||
|
||
now = int(clock.time_msec()) | ||
|
||
return [ | ||
destination | ||
for destination, timings in retry_timings.items() | ||
if timings is None | ||
or timings.retry_last_ts + timings.retry_interval <= now + retry_due_within_ms | ||
] | ||
Comment on lines
+132
to
+141
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I was gonna say "it might be faster to do this logic in the query"... but I guess that would get in the way of using There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, exactly |
||
|
||
|
||
class RetryDestinationLimiter: | ||
def __init__( | ||
self, | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Arguably
.feature