|
5 | 5 |
|
6 | 6 | """ |
7 | 7 |
|
8 | | -import datetime |
9 | 8 | import logging |
10 | 9 | from contextlib import AsyncExitStack |
11 | 10 | from typing import Any, Self, cast |
@@ -449,7 +448,6 @@ def _create_shared_workspace_query( |
449 | 448 | is_search_by_multi_columns: bool, |
450 | 449 | user_groups: list[GroupID], |
451 | 450 | ) -> sql.Select | None: |
452 | | - |
453 | 451 | if workspace_query.workspace_scope is not WorkspaceScope.PRIVATE: |
454 | 452 | assert workspace_query.workspace_scope in ( # nosec |
455 | 453 | WorkspaceScope.SHARED, |
@@ -951,27 +949,32 @@ async def _update_project_workbench_with_lock_and_notify( |
951 | 949 | thread-safe operations on the project document. |
952 | 950 | """ |
953 | 951 |
|
| 952 | + # Get user's primary group ID for notification |
| 953 | + async with self.engine.acquire() as conn: |
| 954 | + user_primary_gid = await self._get_user_primary_group_gid(conn, user_id) |
| 955 | + |
| 956 | + # 10 concurrent calls |
954 | 957 | @exclusive( |
955 | 958 | get_redis_lock_manager_client_sdk(self._app), |
956 | 959 | lock_key=PROJECT_DB_UPDATE_REDIS_LOCK_KEY.format(project_uuid), |
957 | 960 | blocking=True, |
958 | | - blocking_timeout=datetime.timedelta(seconds=30), |
| 961 | + blocking_timeout=None, # NOTE: this is a blocking call, a timeout has undefined effects |
959 | 962 | ) |
960 | 963 | async def _update_workbench_and_notify() -> ( |
961 | | - tuple[ProjectDict, dict[NodeIDStr, Any]] |
| 964 | + tuple[ProjectDict, dict[NodeIDStr, Any], ProjectDocument, int] |
962 | 965 | ): |
963 | | - # Update the workbench |
| 966 | + """This function is protected because |
| 967 | + - the project document and its version must be kept in sync |
| 968 | + """ |
| 969 | + # Update the workbench work since it's atomic |
964 | 970 | updated_project, changed_entries = await self._update_project_workbench( |
965 | 971 | partial_workbench_data, |
966 | 972 | user_id=user_id, |
967 | 973 | project_uuid=f"{project_uuid}", |
968 | 974 | product_name=product_name, |
969 | 975 | allow_workbench_changes=allow_workbench_changes, |
970 | 976 | ) |
971 | | - |
972 | | - # Get user's primary group ID for notification |
973 | | - async with self.engine.acquire() as conn: |
974 | | - user_primary_gid = await self._get_user_primary_group_gid(conn, user_id) |
| 977 | + # the update project with last_modified timestamp latest is the last |
975 | 978 |
|
976 | 979 | # Get the full project with workbench for document creation |
977 | 980 | project_with_workbench = ( |
@@ -1004,17 +1007,23 @@ async def _update_workbench_and_notify() -> ( |
1004 | 1007 | document_version = await increment_and_return_project_document_version( |
1005 | 1008 | redis_client=redis_client_sdk, project_uuid=project_uuid |
1006 | 1009 | ) |
1007 | | - await notify_project_document_updated( |
1008 | | - app=self._app, |
1009 | | - project_id=project_uuid, |
1010 | | - user_primary_gid=user_primary_gid, |
1011 | | - version=document_version, |
1012 | | - document=project_document, |
1013 | | - ) |
1014 | 1010 |
|
1015 | | - return updated_project, changed_entries |
1016 | | - |
1017 | | - return await _update_workbench_and_notify() |
| 1011 | + return updated_project, changed_entries, project_document, document_version |
| 1012 | + |
| 1013 | + ( |
| 1014 | + updated_project, |
| 1015 | + changed_entries, |
| 1016 | + project_document, |
| 1017 | + document_version, |
| 1018 | + ) = await _update_workbench_and_notify() |
| 1019 | + await notify_project_document_updated( |
| 1020 | + app=self._app, |
| 1021 | + project_id=project_uuid, |
| 1022 | + user_primary_gid=user_primary_gid, |
| 1023 | + version=document_version, |
| 1024 | + document=project_document, |
| 1025 | + ) |
| 1026 | + return updated_project, changed_entries |
1018 | 1027 |
|
1019 | 1028 | async def _update_project_workbench( |
1020 | 1029 | self, |
|
0 commit comments