Add an admin API to run background jobs. (#11352)
Instead of having admins poke into the database directly. Can currently run jobs to populate stats and to populate the user directory.
This commit is contained in:
parent
7ae559944a
commit
ea20937084
|
@ -0,0 +1 @@
|
||||||
|
Add admin API to run background jobs.
|
|
@ -2360,8 +2360,8 @@ user_directory:
|
||||||
# indexes were (re)built was before Synapse 1.44, you'll have to
|
# indexes were (re)built was before Synapse 1.44, you'll have to
|
||||||
# rebuild the indexes in order to search through all known users.
|
# rebuild the indexes in order to search through all known users.
|
||||||
# These indexes are built the first time Synapse starts; admins can
|
# These indexes are built the first time Synapse starts; admins can
|
||||||
# manually trigger a rebuild following the instructions at
|
# manually trigger a rebuild via API following the instructions at
|
||||||
# https://matrix-org.github.io/synapse/latest/user_directory.html
|
# https://matrix-org.github.io/synapse/latest/usage/administration/admin_api/background_updates.html#run
|
||||||
#
|
#
|
||||||
# Uncomment to return search results containing all known users, even if that
|
# Uncomment to return search results containing all known users, even if that
|
||||||
# user does not share a room with the requester.
|
# user does not share a room with the requester.
|
||||||
|
|
|
@ -42,7 +42,6 @@ For each update:
|
||||||
`average_items_per_ms` how many items are processed per millisecond based on an exponential average.
|
`average_items_per_ms` how many items are processed per millisecond based on an exponential average.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Enabled
|
## Enabled
|
||||||
|
|
||||||
This API allow pausing background updates.
|
This API allow pausing background updates.
|
||||||
|
@ -82,3 +81,29 @@ The API returns the `enabled` param.
|
||||||
```
|
```
|
||||||
|
|
||||||
There is also a `GET` version which returns the `enabled` state.
|
There is also a `GET` version which returns the `enabled` state.
|
||||||
|
|
||||||
|
|
||||||
|
## Run
|
||||||
|
|
||||||
|
This API schedules a specific background update to run. The job starts immediately after calling the API.
|
||||||
|
|
||||||
|
|
||||||
|
The API is:
|
||||||
|
|
||||||
|
```
|
||||||
|
POST /_synapse/admin/v1/background_updates/start_job
|
||||||
|
```
|
||||||
|
|
||||||
|
with the following body:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"job_name": "populate_stats_process_rooms"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The following JSON body parameters are available:
|
||||||
|
|
||||||
|
- `job_name` - A string which job to run. Valid values are:
|
||||||
|
- `populate_stats_process_rooms` - Recalculate the stats for all rooms.
|
||||||
|
- `regenerate_directory` - Recalculate the [user directory](../../../user_directory.md) if it is stale or out of sync.
|
||||||
|
|
|
@ -6,9 +6,9 @@ on this particular server - i.e. ones which your account shares a room with, or
|
||||||
who are present in a publicly viewable room present on the server.
|
who are present in a publicly viewable room present on the server.
|
||||||
|
|
||||||
The directory info is stored in various tables, which can (typically after
|
The directory info is stored in various tables, which can (typically after
|
||||||
DB corruption) get stale or out of sync. If this happens, for now the
|
DB corruption) get stale or out of sync. If this happens, for now the
|
||||||
solution to fix it is to execute the SQL [here](https://github.com/matrix-org/synapse/blob/master/synapse/storage/schema/main/delta/53/user_dir_populate.sql)
|
solution to fix it is to use the [admin API](usage/administration/admin_api/background_updates.md#run)
|
||||||
and then restart synapse. This should then start a background task to
|
and execute the job `regenerate_directory`. This should then start a background task to
|
||||||
flush the current tables and regenerate the directory.
|
flush the current tables and regenerate the directory.
|
||||||
|
|
||||||
Data model
|
Data model
|
||||||
|
|
|
@ -53,8 +53,8 @@ class UserDirectoryConfig(Config):
|
||||||
# indexes were (re)built was before Synapse 1.44, you'll have to
|
# indexes were (re)built was before Synapse 1.44, you'll have to
|
||||||
# rebuild the indexes in order to search through all known users.
|
# rebuild the indexes in order to search through all known users.
|
||||||
# These indexes are built the first time Synapse starts; admins can
|
# These indexes are built the first time Synapse starts; admins can
|
||||||
# manually trigger a rebuild following the instructions at
|
# manually trigger a rebuild via API following the instructions at
|
||||||
# https://matrix-org.github.io/synapse/latest/user_directory.html
|
# https://matrix-org.github.io/synapse/latest/usage/administration/admin_api/background_updates.html#run
|
||||||
#
|
#
|
||||||
# Uncomment to return search results containing all known users, even if that
|
# Uncomment to return search results containing all known users, even if that
|
||||||
# user does not share a room with the requester.
|
# user does not share a room with the requester.
|
||||||
|
|
|
@ -28,6 +28,7 @@ from synapse.rest.admin._base import admin_patterns, assert_requester_is_admin
|
||||||
from synapse.rest.admin.background_updates import (
|
from synapse.rest.admin.background_updates import (
|
||||||
BackgroundUpdateEnabledRestServlet,
|
BackgroundUpdateEnabledRestServlet,
|
||||||
BackgroundUpdateRestServlet,
|
BackgroundUpdateRestServlet,
|
||||||
|
BackgroundUpdateStartJobRestServlet,
|
||||||
)
|
)
|
||||||
from synapse.rest.admin.devices import (
|
from synapse.rest.admin.devices import (
|
||||||
DeleteDevicesRestServlet,
|
DeleteDevicesRestServlet,
|
||||||
|
@ -261,6 +262,7 @@ def register_servlets(hs: "HomeServer", http_server: HttpServer) -> None:
|
||||||
SendServerNoticeServlet(hs).register(http_server)
|
SendServerNoticeServlet(hs).register(http_server)
|
||||||
BackgroundUpdateEnabledRestServlet(hs).register(http_server)
|
BackgroundUpdateEnabledRestServlet(hs).register(http_server)
|
||||||
BackgroundUpdateRestServlet(hs).register(http_server)
|
BackgroundUpdateRestServlet(hs).register(http_server)
|
||||||
|
BackgroundUpdateStartJobRestServlet(hs).register(http_server)
|
||||||
|
|
||||||
|
|
||||||
def register_servlets_for_client_rest_resource(
|
def register_servlets_for_client_rest_resource(
|
||||||
|
|
|
@ -12,10 +12,15 @@
|
||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
import logging
|
import logging
|
||||||
|
from http import HTTPStatus
|
||||||
from typing import TYPE_CHECKING, Tuple
|
from typing import TYPE_CHECKING, Tuple
|
||||||
|
|
||||||
from synapse.api.errors import SynapseError
|
from synapse.api.errors import SynapseError
|
||||||
from synapse.http.servlet import RestServlet, parse_json_object_from_request
|
from synapse.http.servlet import (
|
||||||
|
RestServlet,
|
||||||
|
assert_params_in_dict,
|
||||||
|
parse_json_object_from_request,
|
||||||
|
)
|
||||||
from synapse.http.site import SynapseRequest
|
from synapse.http.site import SynapseRequest
|
||||||
from synapse.rest.admin._base import admin_patterns, assert_user_is_admin
|
from synapse.rest.admin._base import admin_patterns, assert_user_is_admin
|
||||||
from synapse.types import JsonDict
|
from synapse.types import JsonDict
|
||||||
|
@ -29,37 +34,36 @@ logger = logging.getLogger(__name__)
|
||||||
class BackgroundUpdateEnabledRestServlet(RestServlet):
|
class BackgroundUpdateEnabledRestServlet(RestServlet):
|
||||||
"""Allows temporarily disabling background updates"""
|
"""Allows temporarily disabling background updates"""
|
||||||
|
|
||||||
PATTERNS = admin_patterns("/background_updates/enabled")
|
PATTERNS = admin_patterns("/background_updates/enabled$")
|
||||||
|
|
||||||
def __init__(self, hs: "HomeServer"):
|
def __init__(self, hs: "HomeServer"):
|
||||||
self.group_server = hs.get_groups_server_handler()
|
self._auth = hs.get_auth()
|
||||||
self.is_mine_id = hs.is_mine_id
|
self._data_stores = hs.get_datastores()
|
||||||
self.auth = hs.get_auth()
|
|
||||||
|
|
||||||
self.data_stores = hs.get_datastores()
|
|
||||||
|
|
||||||
async def on_GET(self, request: SynapseRequest) -> Tuple[int, JsonDict]:
|
async def on_GET(self, request: SynapseRequest) -> Tuple[int, JsonDict]:
|
||||||
requester = await self.auth.get_user_by_req(request)
|
requester = await self._auth.get_user_by_req(request)
|
||||||
await assert_user_is_admin(self.auth, requester.user)
|
await assert_user_is_admin(self._auth, requester.user)
|
||||||
|
|
||||||
# We need to check that all configured databases have updates enabled.
|
# We need to check that all configured databases have updates enabled.
|
||||||
# (They *should* all be in sync.)
|
# (They *should* all be in sync.)
|
||||||
enabled = all(db.updates.enabled for db in self.data_stores.databases)
|
enabled = all(db.updates.enabled for db in self._data_stores.databases)
|
||||||
|
|
||||||
return 200, {"enabled": enabled}
|
return HTTPStatus.OK, {"enabled": enabled}
|
||||||
|
|
||||||
async def on_POST(self, request: SynapseRequest) -> Tuple[int, JsonDict]:
|
async def on_POST(self, request: SynapseRequest) -> Tuple[int, JsonDict]:
|
||||||
requester = await self.auth.get_user_by_req(request)
|
requester = await self._auth.get_user_by_req(request)
|
||||||
await assert_user_is_admin(self.auth, requester.user)
|
await assert_user_is_admin(self._auth, requester.user)
|
||||||
|
|
||||||
body = parse_json_object_from_request(request)
|
body = parse_json_object_from_request(request)
|
||||||
|
|
||||||
enabled = body.get("enabled", True)
|
enabled = body.get("enabled", True)
|
||||||
|
|
||||||
if not isinstance(enabled, bool):
|
if not isinstance(enabled, bool):
|
||||||
raise SynapseError(400, "'enabled' parameter must be a boolean")
|
raise SynapseError(
|
||||||
|
HTTPStatus.BAD_REQUEST, "'enabled' parameter must be a boolean"
|
||||||
|
)
|
||||||
|
|
||||||
for db in self.data_stores.databases:
|
for db in self._data_stores.databases:
|
||||||
db.updates.enabled = enabled
|
db.updates.enabled = enabled
|
||||||
|
|
||||||
# If we're re-enabling them ensure that we start the background
|
# If we're re-enabling them ensure that we start the background
|
||||||
|
@ -67,32 +71,29 @@ class BackgroundUpdateEnabledRestServlet(RestServlet):
|
||||||
if enabled:
|
if enabled:
|
||||||
db.updates.start_doing_background_updates()
|
db.updates.start_doing_background_updates()
|
||||||
|
|
||||||
return 200, {"enabled": enabled}
|
return HTTPStatus.OK, {"enabled": enabled}
|
||||||
|
|
||||||
|
|
||||||
class BackgroundUpdateRestServlet(RestServlet):
|
class BackgroundUpdateRestServlet(RestServlet):
|
||||||
"""Fetch information about background updates"""
|
"""Fetch information about background updates"""
|
||||||
|
|
||||||
PATTERNS = admin_patterns("/background_updates/status")
|
PATTERNS = admin_patterns("/background_updates/status$")
|
||||||
|
|
||||||
def __init__(self, hs: "HomeServer"):
|
def __init__(self, hs: "HomeServer"):
|
||||||
self.group_server = hs.get_groups_server_handler()
|
self._auth = hs.get_auth()
|
||||||
self.is_mine_id = hs.is_mine_id
|
self._data_stores = hs.get_datastores()
|
||||||
self.auth = hs.get_auth()
|
|
||||||
|
|
||||||
self.data_stores = hs.get_datastores()
|
|
||||||
|
|
||||||
async def on_GET(self, request: SynapseRequest) -> Tuple[int, JsonDict]:
|
async def on_GET(self, request: SynapseRequest) -> Tuple[int, JsonDict]:
|
||||||
requester = await self.auth.get_user_by_req(request)
|
requester = await self._auth.get_user_by_req(request)
|
||||||
await assert_user_is_admin(self.auth, requester.user)
|
await assert_user_is_admin(self._auth, requester.user)
|
||||||
|
|
||||||
# We need to check that all configured databases have updates enabled.
|
# We need to check that all configured databases have updates enabled.
|
||||||
# (They *should* all be in sync.)
|
# (They *should* all be in sync.)
|
||||||
enabled = all(db.updates.enabled for db in self.data_stores.databases)
|
enabled = all(db.updates.enabled for db in self._data_stores.databases)
|
||||||
|
|
||||||
current_updates = {}
|
current_updates = {}
|
||||||
|
|
||||||
for db in self.data_stores.databases:
|
for db in self._data_stores.databases:
|
||||||
update = db.updates.get_current_update()
|
update = db.updates.get_current_update()
|
||||||
if not update:
|
if not update:
|
||||||
continue
|
continue
|
||||||
|
@ -104,4 +105,72 @@ class BackgroundUpdateRestServlet(RestServlet):
|
||||||
"average_items_per_ms": update.average_items_per_ms(),
|
"average_items_per_ms": update.average_items_per_ms(),
|
||||||
}
|
}
|
||||||
|
|
||||||
return 200, {"enabled": enabled, "current_updates": current_updates}
|
return HTTPStatus.OK, {"enabled": enabled, "current_updates": current_updates}
|
||||||
|
|
||||||
|
|
||||||
|
class BackgroundUpdateStartJobRestServlet(RestServlet):
|
||||||
|
"""Allows to start specific background updates"""
|
||||||
|
|
||||||
|
PATTERNS = admin_patterns("/background_updates/start_job")
|
||||||
|
|
||||||
|
def __init__(self, hs: "HomeServer"):
|
||||||
|
self._auth = hs.get_auth()
|
||||||
|
self._store = hs.get_datastore()
|
||||||
|
|
||||||
|
async def on_POST(self, request: SynapseRequest) -> Tuple[int, JsonDict]:
|
||||||
|
requester = await self._auth.get_user_by_req(request)
|
||||||
|
await assert_user_is_admin(self._auth, requester.user)
|
||||||
|
|
||||||
|
body = parse_json_object_from_request(request)
|
||||||
|
assert_params_in_dict(body, ["job_name"])
|
||||||
|
|
||||||
|
job_name = body["job_name"]
|
||||||
|
|
||||||
|
if job_name == "populate_stats_process_rooms":
|
||||||
|
jobs = [
|
||||||
|
{
|
||||||
|
"update_name": "populate_stats_process_rooms",
|
||||||
|
"progress_json": "{}",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
elif job_name == "regenerate_directory":
|
||||||
|
jobs = [
|
||||||
|
{
|
||||||
|
"update_name": "populate_user_directory_createtables",
|
||||||
|
"progress_json": "{}",
|
||||||
|
"depends_on": "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"update_name": "populate_user_directory_process_rooms",
|
||||||
|
"progress_json": "{}",
|
||||||
|
"depends_on": "populate_user_directory_createtables",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"update_name": "populate_user_directory_process_users",
|
||||||
|
"progress_json": "{}",
|
||||||
|
"depends_on": "populate_user_directory_process_rooms",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"update_name": "populate_user_directory_cleanup",
|
||||||
|
"progress_json": "{}",
|
||||||
|
"depends_on": "populate_user_directory_process_users",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
else:
|
||||||
|
raise SynapseError(HTTPStatus.BAD_REQUEST, "Invalid job_name")
|
||||||
|
|
||||||
|
try:
|
||||||
|
await self._store.db_pool.simple_insert_many(
|
||||||
|
table="background_updates",
|
||||||
|
values=jobs,
|
||||||
|
desc=f"admin_api_run_{job_name}",
|
||||||
|
)
|
||||||
|
except self._store.db_pool.engine.module.IntegrityError:
|
||||||
|
raise SynapseError(
|
||||||
|
HTTPStatus.BAD_REQUEST,
|
||||||
|
"Job %s is already in queue of background updates." % (job_name,),
|
||||||
|
)
|
||||||
|
|
||||||
|
self._store.db_pool.updates.start_doing_background_updates()
|
||||||
|
|
||||||
|
return HTTPStatus.OK, {}
|
||||||
|
|
|
@ -122,6 +122,8 @@ class BackgroundUpdater:
|
||||||
|
|
||||||
def start_doing_background_updates(self) -> None:
|
def start_doing_background_updates(self) -> None:
|
||||||
if self.enabled:
|
if self.enabled:
|
||||||
|
# if we start a new background update, not all updates are done.
|
||||||
|
self._all_done = False
|
||||||
run_as_background_process("background_updates", self.run_background_updates)
|
run_as_background_process("background_updates", self.run_background_updates)
|
||||||
|
|
||||||
async def run_background_updates(self, sleep: bool = True) -> None:
|
async def run_background_updates(self, sleep: bool = True) -> None:
|
||||||
|
|
|
@ -11,8 +11,13 @@
|
||||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
from http import HTTPStatus
|
||||||
|
from typing import Collection
|
||||||
|
|
||||||
|
from parameterized import parameterized
|
||||||
|
|
||||||
import synapse.rest.admin
|
import synapse.rest.admin
|
||||||
|
from synapse.api.errors import Codes
|
||||||
from synapse.rest.client import login
|
from synapse.rest.client import login
|
||||||
from synapse.server import HomeServer
|
from synapse.server import HomeServer
|
||||||
|
|
||||||
|
@ -30,6 +35,60 @@ class BackgroundUpdatesTestCase(unittest.HomeserverTestCase):
|
||||||
self.admin_user = self.register_user("admin", "pass", admin=True)
|
self.admin_user = self.register_user("admin", "pass", admin=True)
|
||||||
self.admin_user_tok = self.login("admin", "pass")
|
self.admin_user_tok = self.login("admin", "pass")
|
||||||
|
|
||||||
|
@parameterized.expand(
|
||||||
|
[
|
||||||
|
("GET", "/_synapse/admin/v1/background_updates/enabled"),
|
||||||
|
("POST", "/_synapse/admin/v1/background_updates/enabled"),
|
||||||
|
("GET", "/_synapse/admin/v1/background_updates/status"),
|
||||||
|
("POST", "/_synapse/admin/v1/background_updates/start_job"),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
def test_requester_is_no_admin(self, method: str, url: str):
|
||||||
|
"""
|
||||||
|
If the user is not a server admin, an error 403 is returned.
|
||||||
|
"""
|
||||||
|
|
||||||
|
self.register_user("user", "pass", admin=False)
|
||||||
|
other_user_tok = self.login("user", "pass")
|
||||||
|
|
||||||
|
channel = self.make_request(
|
||||||
|
method,
|
||||||
|
url,
|
||||||
|
content={},
|
||||||
|
access_token=other_user_tok,
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(HTTPStatus.FORBIDDEN, channel.code, msg=channel.json_body)
|
||||||
|
self.assertEqual(Codes.FORBIDDEN, channel.json_body["errcode"])
|
||||||
|
|
||||||
|
def test_invalid_parameter(self):
|
||||||
|
"""
|
||||||
|
If parameters are invalid, an error is returned.
|
||||||
|
"""
|
||||||
|
url = "/_synapse/admin/v1/background_updates/start_job"
|
||||||
|
|
||||||
|
# empty content
|
||||||
|
channel = self.make_request(
|
||||||
|
"POST",
|
||||||
|
url,
|
||||||
|
content={},
|
||||||
|
access_token=self.admin_user_tok,
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(HTTPStatus.BAD_REQUEST, channel.code, msg=channel.json_body)
|
||||||
|
self.assertEqual(Codes.MISSING_PARAM, channel.json_body["errcode"])
|
||||||
|
|
||||||
|
# job_name invalid
|
||||||
|
channel = self.make_request(
|
||||||
|
"POST",
|
||||||
|
url,
|
||||||
|
content={"job_name": "unknown"},
|
||||||
|
access_token=self.admin_user_tok,
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(HTTPStatus.BAD_REQUEST, channel.code, msg=channel.json_body)
|
||||||
|
self.assertEqual(Codes.UNKNOWN, channel.json_body["errcode"])
|
||||||
|
|
||||||
def _register_bg_update(self):
|
def _register_bg_update(self):
|
||||||
"Adds a bg update but doesn't start it"
|
"Adds a bg update but doesn't start it"
|
||||||
|
|
||||||
|
@ -60,7 +119,7 @@ class BackgroundUpdatesTestCase(unittest.HomeserverTestCase):
|
||||||
"/_synapse/admin/v1/background_updates/status",
|
"/_synapse/admin/v1/background_updates/status",
|
||||||
access_token=self.admin_user_tok,
|
access_token=self.admin_user_tok,
|
||||||
)
|
)
|
||||||
self.assertEqual(200, int(channel.result["code"]), msg=channel.result["body"])
|
self.assertEqual(HTTPStatus.OK, channel.code, msg=channel.json_body)
|
||||||
|
|
||||||
# Background updates should be enabled, but none should be running.
|
# Background updates should be enabled, but none should be running.
|
||||||
self.assertDictEqual(
|
self.assertDictEqual(
|
||||||
|
@ -82,7 +141,7 @@ class BackgroundUpdatesTestCase(unittest.HomeserverTestCase):
|
||||||
"/_synapse/admin/v1/background_updates/status",
|
"/_synapse/admin/v1/background_updates/status",
|
||||||
access_token=self.admin_user_tok,
|
access_token=self.admin_user_tok,
|
||||||
)
|
)
|
||||||
self.assertEqual(200, int(channel.result["code"]), msg=channel.result["body"])
|
self.assertEqual(HTTPStatus.OK, channel.code, msg=channel.json_body)
|
||||||
|
|
||||||
# Background updates should be enabled, and one should be running.
|
# Background updates should be enabled, and one should be running.
|
||||||
self.assertDictEqual(
|
self.assertDictEqual(
|
||||||
|
@ -114,7 +173,7 @@ class BackgroundUpdatesTestCase(unittest.HomeserverTestCase):
|
||||||
"/_synapse/admin/v1/background_updates/enabled",
|
"/_synapse/admin/v1/background_updates/enabled",
|
||||||
access_token=self.admin_user_tok,
|
access_token=self.admin_user_tok,
|
||||||
)
|
)
|
||||||
self.assertEqual(200, int(channel.result["code"]), msg=channel.result["body"])
|
self.assertEqual(HTTPStatus.OK, channel.code, msg=channel.json_body)
|
||||||
self.assertDictEqual(channel.json_body, {"enabled": True})
|
self.assertDictEqual(channel.json_body, {"enabled": True})
|
||||||
|
|
||||||
# Disable the BG updates
|
# Disable the BG updates
|
||||||
|
@ -124,7 +183,7 @@ class BackgroundUpdatesTestCase(unittest.HomeserverTestCase):
|
||||||
content={"enabled": False},
|
content={"enabled": False},
|
||||||
access_token=self.admin_user_tok,
|
access_token=self.admin_user_tok,
|
||||||
)
|
)
|
||||||
self.assertEqual(200, int(channel.result["code"]), msg=channel.result["body"])
|
self.assertEqual(HTTPStatus.OK, channel.code, msg=channel.json_body)
|
||||||
self.assertDictEqual(channel.json_body, {"enabled": False})
|
self.assertDictEqual(channel.json_body, {"enabled": False})
|
||||||
|
|
||||||
# Advance a bit and get the current status, note this will finish the in
|
# Advance a bit and get the current status, note this will finish the in
|
||||||
|
@ -137,7 +196,7 @@ class BackgroundUpdatesTestCase(unittest.HomeserverTestCase):
|
||||||
"/_synapse/admin/v1/background_updates/status",
|
"/_synapse/admin/v1/background_updates/status",
|
||||||
access_token=self.admin_user_tok,
|
access_token=self.admin_user_tok,
|
||||||
)
|
)
|
||||||
self.assertEqual(200, int(channel.result["code"]), msg=channel.result["body"])
|
self.assertEqual(HTTPStatus.OK, channel.code, msg=channel.json_body)
|
||||||
self.assertDictEqual(
|
self.assertDictEqual(
|
||||||
channel.json_body,
|
channel.json_body,
|
||||||
{
|
{
|
||||||
|
@ -162,7 +221,7 @@ class BackgroundUpdatesTestCase(unittest.HomeserverTestCase):
|
||||||
"/_synapse/admin/v1/background_updates/status",
|
"/_synapse/admin/v1/background_updates/status",
|
||||||
access_token=self.admin_user_tok,
|
access_token=self.admin_user_tok,
|
||||||
)
|
)
|
||||||
self.assertEqual(200, int(channel.result["code"]), msg=channel.result["body"])
|
self.assertEqual(HTTPStatus.OK, channel.code, msg=channel.json_body)
|
||||||
|
|
||||||
# There should be no change from the previous /status response.
|
# There should be no change from the previous /status response.
|
||||||
self.assertDictEqual(
|
self.assertDictEqual(
|
||||||
|
@ -188,7 +247,7 @@ class BackgroundUpdatesTestCase(unittest.HomeserverTestCase):
|
||||||
content={"enabled": True},
|
content={"enabled": True},
|
||||||
access_token=self.admin_user_tok,
|
access_token=self.admin_user_tok,
|
||||||
)
|
)
|
||||||
self.assertEqual(200, int(channel.result["code"]), msg=channel.result["body"])
|
self.assertEqual(HTTPStatus.OK, channel.code, msg=channel.json_body)
|
||||||
|
|
||||||
self.assertDictEqual(channel.json_body, {"enabled": True})
|
self.assertDictEqual(channel.json_body, {"enabled": True})
|
||||||
|
|
||||||
|
@ -199,7 +258,7 @@ class BackgroundUpdatesTestCase(unittest.HomeserverTestCase):
|
||||||
"/_synapse/admin/v1/background_updates/status",
|
"/_synapse/admin/v1/background_updates/status",
|
||||||
access_token=self.admin_user_tok,
|
access_token=self.admin_user_tok,
|
||||||
)
|
)
|
||||||
self.assertEqual(200, int(channel.result["code"]), msg=channel.result["body"])
|
self.assertEqual(HTTPStatus.OK, channel.code, msg=channel.json_body)
|
||||||
|
|
||||||
# Background updates should be enabled and making progress.
|
# Background updates should be enabled and making progress.
|
||||||
self.assertDictEqual(
|
self.assertDictEqual(
|
||||||
|
@ -216,3 +275,82 @@ class BackgroundUpdatesTestCase(unittest.HomeserverTestCase):
|
||||||
"enabled": True,
|
"enabled": True,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@parameterized.expand(
|
||||||
|
[
|
||||||
|
("populate_stats_process_rooms", ["populate_stats_process_rooms"]),
|
||||||
|
(
|
||||||
|
"regenerate_directory",
|
||||||
|
[
|
||||||
|
"populate_user_directory_createtables",
|
||||||
|
"populate_user_directory_process_rooms",
|
||||||
|
"populate_user_directory_process_users",
|
||||||
|
"populate_user_directory_cleanup",
|
||||||
|
],
|
||||||
|
),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
def test_start_backround_job(self, job_name: str, updates: Collection[str]):
|
||||||
|
"""
|
||||||
|
Test that background updates add to database and be processed.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
job_name: name of the job to call with API
|
||||||
|
updates: collection of background updates to be started
|
||||||
|
"""
|
||||||
|
|
||||||
|
# no background update is waiting
|
||||||
|
self.assertTrue(
|
||||||
|
self.get_success(
|
||||||
|
self.store.db_pool.updates.has_completed_background_updates()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
channel = self.make_request(
|
||||||
|
"POST",
|
||||||
|
"/_synapse/admin/v1/background_updates/start_job",
|
||||||
|
content={"job_name": job_name},
|
||||||
|
access_token=self.admin_user_tok,
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(HTTPStatus.OK, channel.code, msg=channel.json_body)
|
||||||
|
|
||||||
|
# test that each background update is waiting now
|
||||||
|
for update in updates:
|
||||||
|
self.assertFalse(
|
||||||
|
self.get_success(
|
||||||
|
self.store.db_pool.updates.has_completed_background_update(update)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
self.wait_for_background_updates()
|
||||||
|
|
||||||
|
# background updates are done
|
||||||
|
self.assertTrue(
|
||||||
|
self.get_success(
|
||||||
|
self.store.db_pool.updates.has_completed_background_updates()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_start_backround_job_twice(self):
|
||||||
|
"""Test that add a background update twice return an error."""
|
||||||
|
|
||||||
|
# add job to database
|
||||||
|
self.get_success(
|
||||||
|
self.store.db_pool.simple_insert(
|
||||||
|
table="background_updates",
|
||||||
|
values={
|
||||||
|
"update_name": "populate_stats_process_rooms",
|
||||||
|
"progress_json": "{}",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
channel = self.make_request(
|
||||||
|
"POST",
|
||||||
|
"/_synapse/admin/v1/background_updates/start_job",
|
||||||
|
content={"job_name": "populate_stats_process_rooms"},
|
||||||
|
access_token=self.admin_user_tok,
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(HTTPStatus.BAD_REQUEST, channel.code, msg=channel.json_body)
|
||||||
|
|
Loading…
Reference in New Issue