From e3344dc0c3a11b0bb661657da51655a0b02a4bfc Mon Sep 17 00:00:00 2001 From: Andrew Morgan <1342360+anoadragon453@users.noreply.github.com> Date: Thu, 9 Oct 2025 15:15:13 +0100 Subject: [PATCH] Expose `defer_to_threadpool` in the module API (#19032) --- changelog.d/19032.feature | 1 + synapse/module_api/__init__.py | 29 +++++++++++++++++++++++++++++ 2 files changed, 30 insertions(+) create mode 100644 changelog.d/19032.feature diff --git a/changelog.d/19032.feature b/changelog.d/19032.feature new file mode 100644 index 000000000..2e3bdbe39 --- /dev/null +++ b/changelog.d/19032.feature @@ -0,0 +1 @@ +Expose a `defer_to_threadpool` function in the Synapse Module API that allows modules to run a function on a separate thread in a custom threadpool. \ No newline at end of file diff --git a/synapse/module_api/__init__.py b/synapse/module_api/__init__.py index 12a31dd2a..ea0887966 100644 --- a/synapse/module_api/__init__.py +++ b/synapse/module_api/__init__.py @@ -43,6 +43,7 @@ from typing_extensions import Concatenate, ParamSpec from twisted.internet import defer from twisted.internet.interfaces import IDelayedCall +from twisted.python.threadpool import ThreadPool from twisted.web.resource import Resource from synapse.api import errors @@ -79,6 +80,7 @@ from synapse.http.servlet import parse_json_object_from_request from synapse.http.site import SynapseRequest from synapse.logging.context import ( defer_to_thread, + defer_to_threadpool, make_deferred_yieldable, run_in_background, ) @@ -1733,6 +1735,33 @@ class ModuleApi: """ return await defer_to_thread(self._hs.get_reactor(), f, *args, **kwargs) + async def defer_to_threadpool( + self, + threadpool: ThreadPool, + f: Callable[P, T], + *args: P.args, + **kwargs: P.kwargs, + ) -> T: + """Runs the given function in a separate thread from the given thread pool. + + Allows specifying a custom thread pool instead of using the default Synapse + one. To use the default Synapse threadpool, use `defer_to_thread` instead. + + Added in Synapse v1.140.0. + + Args: + threadpool: The thread pool to use. + f: The function to run. + args: The function's arguments. + kwargs: The function's keyword arguments. + + Returns: + The return value of the function once ran in a thread. + """ + return await defer_to_threadpool( + self._hs.get_reactor(), threadpool, f, *args, **kwargs + ) + async def check_username(self, username: str) -> None: """Checks if the provided username uses the grammar defined in the Matrix specification, and is already being used by an existing user.