Skip to content

Commit 56e4545

Browse files
Move search index update to background (#639)
* Move search index update to background * Update gramps_webapi/api/resources/base.py Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Fix typo in DelimitedList --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
1 parent ffc5bbd commit 56e4545

File tree

3 files changed

+68
-57
lines changed

3 files changed

+68
-57
lines changed

gramps_webapi/api/resources/base.py

Lines changed: 25 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,12 @@
1919

2020
"""Base for Gramps object API resources."""
2121

22-
import json
23-
from typing import Dict, List, TypeVar
22+
from typing import TypeVar
2423

2524
import gramps_ql as gql
2625
import object_ql as oql
2726
from flask import abort, request
27+
from flask_jwt_extended import get_jwt_identity
2828
from gramps.gen.const import GRAMPS_LOCALE as glocale
2929
from gramps.gen.db import DbTxn
3030
from gramps.gen.db.base import DbReadBase
@@ -37,12 +37,13 @@
3737
from webargs import fields, validate
3838

3939
from gramps_webapi.api.search.indexer import SemanticSearchIndexer
40-
from gramps_webapi.types import Handle, ResponseReturnValue
40+
from gramps_webapi.types import ResponseReturnValue
4141

4242
from ...auth.const import PERM_ADD_OBJ, PERM_DEL_OBJ, PERM_EDIT_OBJ
4343
from ...const import GRAMPS_OBJECT_PLURAL
4444
from ..auth import require_permissions
4545
from ..search import SearchIndexer, get_search_indexer, get_semantic_search_indexer
46+
from ..tasks import run_task, update_search_indices_from_transaction
4647
from ..util import (
4748
check_quota_people,
4849
get_db_handle,
@@ -82,7 +83,7 @@ class GrampsObjectResourceHelper(GrampsJSONEncoder):
8283

8384
gramps_class_name: str
8485

85-
def full_object(self, obj: T, args: Dict, locale: GrampsLocale = glocale) -> T:
86+
def full_object(self, obj: T, args: dict, locale: GrampsLocale = glocale) -> T:
8687
"""Get the full object with extended attributes and backlinks."""
8788
if args.get("backlinks"):
8889
obj.backlinks = get_backlinks(self.db_handle, obj.handle)
@@ -104,21 +105,21 @@ def full_object(self, obj: T, args: Dict, locale: GrampsLocale = glocale) -> T:
104105
)
105106
return obj
106107

107-
def object_extend(self, obj: T, args: Dict, locale: GrampsLocale = glocale) -> T:
108+
def object_extend(self, obj: T, args: dict, locale: GrampsLocale = glocale) -> T:
108109
"""Extend the base object attributes as needed."""
109110
if "extend" in args:
110111
obj.extended = get_extended_attributes(self.db_handle, obj, args)
111112
return obj
112113

113114
def sort_objects(
114-
self, objects: List[GrampsObject], args: Dict, locale: GrampsLocale = glocale
115-
) -> List:
115+
self, objects: list[GrampsObject], args: dict, locale: GrampsLocale = glocale
116+
) -> list:
116117
"""Sort the list of objects as needed."""
117118
return sort_objects(
118119
self.db_handle, self.gramps_class_name, objects, args, locale=locale
119120
)
120121

121-
def match_dates(self, objects: List[GrampsObject], date: str) -> List[GrampsObject]:
122+
def match_dates(self, objects: list[GrampsObject], date: str) -> list[GrampsObject]:
122123
"""If supported filter objects using date mask."""
123124
if self.gramps_class_name in ["Event", "Media", "Citation"]:
124125
return match_dates(objects, date)
@@ -232,7 +233,7 @@ class GrampsObjectResource(GrampsObjectResourceHelper, Resource):
232233
},
233234
location="query",
234235
)
235-
def get(self, args: Dict, handle: str) -> ResponseReturnValue:
236+
def get(self, args: dict, handle: str) -> ResponseReturnValue:
236237
"""Get the object."""
237238
try:
238239
obj = self.get_object_from_handle(handle)
@@ -290,17 +291,13 @@ def put(self, handle: str) -> ResponseReturnValue:
290291
trans_dict = transaction_to_json(trans)
291292
# update search index
292293
tree = get_tree_from_jwt_or_fail()
293-
indexer: SearchIndexer = get_search_indexer(tree)
294-
for _trans_dict in trans_dict:
295-
handle = _trans_dict["handle"]
296-
class_name = _trans_dict["_class"]
297-
indexer.add_or_update_object(handle, db_handle, class_name)
298-
if app_has_semantic_search():
299-
semantic_indexer: SemanticSearchIndexer = get_semantic_search_indexer(tree)
300-
for _trans_dict in trans_dict:
301-
handle = _trans_dict["handle"]
302-
class_name = _trans_dict["_class"]
303-
semantic_indexer.add_or_update_object(handle, db_handle, class_name)
294+
user_id = get_jwt_identity()
295+
run_task(
296+
update_search_indices_from_transaction,
297+
trans_dict=trans_dict,
298+
tree=tree,
299+
user_id=user_id,
300+
)
304301
return self.response(200, trans_dict, total_items=len(trans_dict))
305302

306303

@@ -384,7 +381,7 @@ class GrampsObjectsResource(GrampsObjectResourceHelper, Resource):
384381
},
385382
location="query",
386383
)
387-
def get(self, args: Dict) -> ResponseReturnValue:
384+
def get(self, args: dict) -> ResponseReturnValue:
388385
"""Get all objects."""
389386
locale = get_locale_for_language(args["locale"], default=True)
390387
if "gramps_id" in args:
@@ -486,17 +483,13 @@ def post(self) -> ResponseReturnValue:
486483
update_usage_people()
487484
# update search index
488485
tree = get_tree_from_jwt_or_fail()
489-
indexer: SearchIndexer = get_search_indexer(tree)
490-
for _trans_dict in trans_dict:
491-
handle = _trans_dict["handle"]
492-
class_name = _trans_dict["_class"]
493-
indexer.add_or_update_object(handle, db_handle, class_name)
494-
if app_has_semantic_search():
495-
semantic_indexer: SemanticSearchIndexer = get_semantic_search_indexer(tree)
496-
for _trans_dict in trans_dict:
497-
handle = _trans_dict["handle"]
498-
class_name = _trans_dict["_class"]
499-
semantic_indexer.add_or_update_object(handle, db_handle, class_name)
486+
user_id = get_jwt_identity()
487+
run_task(
488+
update_search_indices_from_transaction,
489+
trans_dict=trans_dict,
490+
tree=tree,
491+
user_id=user_id,
492+
)
500493
return self.response(201, trans_dict, total_items=len(trans_dict))
501494

502495

gramps_webapi/api/resources/objects.py

Lines changed: 19 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -36,25 +36,24 @@
3636
from ...auth.const import PERM_ADD_OBJ, PERM_DEL_OBJ_BATCH, PERM_EDIT_OBJ
3737
from ...const import GRAMPS_OBJECT_PLURAL
3838
from ..auth import require_permissions
39-
from ..search import get_search_indexer, get_semantic_search_indexer
40-
from ..tasks import AsyncResult, delete_objects, make_task_response, run_task
39+
from ..tasks import (
40+
AsyncResult,
41+
delete_objects,
42+
make_task_response,
43+
run_task,
44+
update_search_indices_from_transaction,
45+
)
4146
from ..util import (
4247
abort_with_message,
4348
check_quota_people,
4449
get_db_handle,
45-
get_tree_from_jwt,
50+
get_tree_from_jwt_or_fail,
4651
gramps_object_from_dict,
4752
update_usage_people,
4853
use_args,
4954
)
5055
from . import FreshProtectedResource, ProtectedResource
51-
from .util import (
52-
add_object,
53-
app_has_semantic_search,
54-
fix_object_dict,
55-
transaction_to_json,
56-
validate_object_dict,
57-
)
56+
from .util import add_object, fix_object_dict, transaction_to_json, validate_object_dict
5857

5958

6059
class CreateObjectsResource(ProtectedResource):
@@ -99,20 +98,15 @@ def post(self) -> ResponseReturnValue:
9998
trans_dict = transaction_to_json(trans)
10099
if number_new_people:
101100
update_usage_people()
102-
# update search index
103-
tree = get_tree_from_jwt()
104-
assert tree is not None # mypy
105-
indexer = get_search_indexer(tree)
106-
for _trans_dict in trans_dict:
107-
handle = _trans_dict["handle"]
108-
class_name = _trans_dict["_class"]
109-
indexer.add_or_update_object(handle, db_handle, class_name)
110-
if app_has_semantic_search():
111-
indexer_semantic = get_semantic_search_indexer(tree)
112-
for _trans_dict in trans_dict:
113-
handle = _trans_dict["handle"]
114-
class_name = _trans_dict["_class"]
115-
indexer_semantic.add_or_update_object(handle, db_handle, class_name)
101+
# update search indices
102+
tree = get_tree_from_jwt_or_fail()
103+
user_id = get_jwt_identity()
104+
run_task(
105+
update_search_indices_from_transaction,
106+
trans_dict=trans_dict,
107+
tree=tree,
108+
user_id=user_id,
109+
)
116110
res = Response(
117111
response=json.dumps(trans_dict),
118112
status=201,
@@ -139,7 +133,7 @@ class DeleteObjectsResource(FreshProtectedResource):
139133
def post(self, args) -> ResponseReturnValue:
140134
"""Delete the objects."""
141135
require_permissions([PERM_DEL_OBJ_BATCH])
142-
tree = get_tree_from_jwt()
136+
tree = get_tree_from_jwt_or_fail()
143137
user_id = get_jwt_identity()
144138
task = run_task(
145139
delete_objects,

gramps_webapi/api/tasks.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -571,3 +571,27 @@ def old_unchanged(db: DbReadBase, class_name: str, handle: str, old_data: Dict)
571571
if diff_items(class_name, old_data, obj_dict):
572572
return False
573573
return True
574+
575+
576+
@shared_task(bind=True)
577+
def update_search_indices_from_transaction(
578+
self, trans_dict: list[dict], tree: str, user_id: str
579+
) -> None:
580+
"""Update the search indices from a transaction."""
581+
db_handle = get_db_outside_request(
582+
tree=tree, view_private=True, readonly=True, user_id=user_id
583+
)
584+
try:
585+
indexer = get_search_indexer(tree)
586+
for _trans_dict in trans_dict:
587+
handle = _trans_dict["handle"]
588+
class_name = _trans_dict["_class"]
589+
indexer.add_or_update_object(handle, db_handle, class_name)
590+
if app_has_semantic_search():
591+
indexer_semantic = get_semantic_search_indexer(tree)
592+
for _trans_dict in trans_dict:
593+
handle = _trans_dict["handle"]
594+
class_name = _trans_dict["_class"]
595+
indexer_semantic.add_or_update_object(handle, db_handle, class_name)
596+
finally:
597+
close_db(db_handle)

0 commit comments

Comments
 (0)