1
0
mirror of https://github.com/ansible/awx.git synced 2024-10-30 13:55:31 +03:00

work around a limitation in postgres notify to properly support copying

postgres has a limitation on its notify message size (8k), and the
messages we generate for deep copying functionality easily go over this
limit; instead of passing a giant nested data structure across the
message bus, this change makes it so that we temporarily store the JSON
structure in memcached, and look it up from *within* the task

see: https://github.com/ansible/tower/issues/4162
This commit is contained in:
Ryan Petrello 2020-03-02 16:35:06 -05:00
parent 770b457430
commit 1caa2e0287
No known key found for this signature in database
GPG Key ID: F2AA5F2122351777
2 changed files with 14 additions and 2 deletions

View File

@ -5,10 +5,12 @@
import inspect import inspect
import logging import logging
import time import time
import uuid
import urllib.parse import urllib.parse
# Django # Django
from django.conf import settings from django.conf import settings
from django.core.cache import cache
from django.db import connection from django.db import connection
from django.db.models.fields import FieldDoesNotExist from django.db.models.fields import FieldDoesNotExist
from django.db.models.fields.related import OneToOneRel from django.db.models.fields.related import OneToOneRel
@ -973,6 +975,11 @@ class CopyAPIView(GenericAPIView):
if hasattr(new_obj, 'admin_role') and request.user not in new_obj.admin_role.members.all(): if hasattr(new_obj, 'admin_role') and request.user not in new_obj.admin_role.members.all():
new_obj.admin_role.members.add(request.user) new_obj.admin_role.members.add(request.user)
if sub_objs: if sub_objs:
# store the copied object dict into memcached, because it's
# often too large for postgres' notification bus
# (which has a default maximum message size of 8k)
key = 'deep-copy-{}'.format(str(uuid.uuid4()))
cache.set(key, sub_objs, timeout=3600)
permission_check_func = None permission_check_func = None
if hasattr(type(self), 'deep_copy_permission_check_func'): if hasattr(type(self), 'deep_copy_permission_check_func'):
permission_check_func = ( permission_check_func = (
@ -980,7 +987,7 @@ class CopyAPIView(GenericAPIView):
) )
trigger_delayed_deep_copy( trigger_delayed_deep_copy(
self.model.__module__, self.model.__name__, self.model.__module__, self.model.__name__,
obj.pk, new_obj.pk, request.user.pk, sub_objs, obj.pk, new_obj.pk, request.user.pk, key,
permission_check_func=permission_check_func permission_check_func=permission_check_func
) )
serializer = self._get_copy_return_serializer(new_obj) serializer = self._get_copy_return_serializer(new_obj)

View File

@ -2856,8 +2856,13 @@ def _reconstruct_relationships(copy_mapping):
@task(queue=get_local_queuename) @task(queue=get_local_queuename)
def deep_copy_model_obj( def deep_copy_model_obj(
model_module, model_name, obj_pk, new_obj_pk, model_module, model_name, obj_pk, new_obj_pk,
user_pk, sub_obj_list, permission_check_func=None user_pk, uuid, permission_check_func=None
): ):
sub_obj_list = cache.get(uuid)
if sub_obj_list is None:
logger.error('Deep copy {} from {} to {} failed unexpectedly.'.format(model_name, obj_pk, new_obj_pk))
return
logger.debug('Deep copy {} from {} to {}.'.format(model_name, obj_pk, new_obj_pk)) logger.debug('Deep copy {} from {} to {}.'.format(model_name, obj_pk, new_obj_pk))
from awx.api.generics import CopyAPIView from awx.api.generics import CopyAPIView
from awx.main.signals import disable_activity_stream from awx.main.signals import disable_activity_stream