summary refs log tree commit diff
path: root/synapse/config/_base.py
diff options
context:
space:
mode:
authorErik Johnston <erik@matrix.org>2020-07-16 14:06:28 +0100
committerGitHub <noreply@github.com>2020-07-16 14:06:28 +0100
commit649a7ead5c4bd2d8b7c486ac1a68ce4e41d49767 (patch)
tree2a3ee5836578e99c15a8c342934c6e7d056563a2 /synapse/config/_base.py
parentMerge pull request #7866 from matrix-org/rav/fix_guest_user_id (diff)
downloadsynapse-649a7ead5c4bd2d8b7c486ac1a68ce4e41d49767.tar.xz
Add ability to run multiple pusher instances (#7855)
This reuses the same scheme as federation sender sharding
Diffstat (limited to 'synapse/config/_base.py')
-rw-r--r--synapse/config/_base.py38
1 files changed, 36 insertions, 2 deletions
diff --git a/synapse/config/_base.py b/synapse/config/_base.py
index 1391e5fc43..fd137853b1 100644
--- a/synapse/config/_base.py
+++ b/synapse/config/_base.py
@@ -19,9 +19,11 @@ import argparse
 import errno
 import os
 from collections import OrderedDict
+from hashlib import sha256
 from textwrap import dedent
-from typing import Any, MutableMapping, Optional
+from typing import Any, List, MutableMapping, Optional
 
+import attr
 import yaml
 
 
@@ -717,4 +719,36 @@ def find_config_files(search_paths):
     return config_files
 
 
-__all__ = ["Config", "RootConfig"]
+@attr.s
+class ShardedWorkerHandlingConfig:
+    """Algorithm for choosing which instance is responsible for handling some
+    sharded work.
+
+    For example, the federation senders use this to determine which instances
+    handles sending stuff to a given destination (which is used as the `key`
+    below).
+    """
+
+    instances = attr.ib(type=List[str])
+
+    def should_handle(self, instance_name: str, key: str) -> bool:
+        """Whether this instance is responsible for handling the given key.
+        """
+
+        # If multiple instances are not defined we always return true.
+        if not self.instances or len(self.instances) == 1:
+            return True
+
+        # We shard by taking the hash, modulo it by the number of instances and
+        # then checking whether this instance matches the instance at that
+        # index.
+        #
+        # (Technically this introduces some bias and is not entirely uniform,
+        # but since the hash is so large the bias is ridiculously small).
+        dest_hash = sha256(key.encode("utf8")).digest()
+        dest_int = int.from_bytes(dest_hash, byteorder="little")
+        remainder = dest_int % (len(self.instances))
+        return self.instances[remainder] == instance_name
+
+
+__all__ = ["Config", "RootConfig", "ShardedWorkerHandlingConfig"]