From 5d36038a752bb9b73c885ca4c2518394be5cc140 Mon Sep 17 00:00:00 2001 From: Davis Muro Date: Thu, 24 Nov 2022 11:01:27 +0300 Subject: [PATCH] Asynchronously propagate permissions to avoid internal server errors - Avoids 500 status codes when trying to reach the External KPI service due to network issues or unexpected service unavailability --- onadata/libs/models/share_project.py | 5 +++-- onadata/libs/utils/project_utils.py | 14 ++++++++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/onadata/libs/models/share_project.py b/onadata/libs/models/share_project.py index e4363f5073..0eb10adbb7 100644 --- a/onadata/libs/models/share_project.py +++ b/onadata/libs/models/share_project.py @@ -10,7 +10,8 @@ EditorMinorRole, EditorRole) from onadata.libs.utils.cache_tools import (PROJ_OWNER_CACHE, PROJ_PERM_CACHE, safe_delete) -from onadata.libs.utils.project_utils import propagate_project_permissions +from onadata.libs.utils.project_utils import \ + propagate_project_permissions_async # pylint: disable=invalid-name User = get_user_model() @@ -86,7 +87,7 @@ def save(self, **kwargs): safe_delete(f"{PROJ_PERM_CACHE}{self.project.pk}") # propagate permissions - propagate_project_permissions(self.project) + propagate_project_permissions_async.apply_async(args=[self.project.pk]) @transaction.atomic() def __remove_user(self): diff --git a/onadata/libs/utils/project_utils.py b/onadata/libs/utils/project_utils.py index 4479c0b4f5..9e1dbc128d 100644 --- a/onadata/libs/utils/project_utils.py +++ b/onadata/libs/utils/project_utils.py @@ -202,6 +202,20 @@ def assign_change_asset_permission( ) return resp +@app.task(bind=True, max_retries=3) +def propagate_project_permissions_async(self, project_id: int, headers: Optional[dict] = None, use_asset_owner_auth: bool = True): + """ + Asynchronously propagates Project Permissions to the Formbuilder assets within the project + """ + try: + project = Project.objects.get(id=project_id) + propagate_project_permissions(project, headers, use_asset_owner_auth) + except (Project.DoesNotExist, ExternalServiceRequestError) as e: + if self.request.retries > 3: + msg = f"Failed to propagate asset permissions for Project {project_id}" + report_exception(msg, e, sys.exc_info()) + self.retry(exc=e, countdown=60 * self.request.retries) + def propagate_project_permissions( project: Project, headers: Optional[dict] = None, use_asset_owner_auth: bool = True