From 5433af6716dd82cf206a7ebec8b9d6e0a4592889 Mon Sep 17 00:00:00 2001 From: AlanCoding Date: Mon, 4 Nov 2019 22:28:49 -0500 Subject: [PATCH 1/2] Reduce API response times by caching migration flag --- awx/main/apps.py | 9 +++++++++ awx/main/middleware.py | 14 +++++++++----- awx/main/tasks.py | 6 ++++++ 3 files changed, 24 insertions(+), 5 deletions(-) diff --git a/awx/main/apps.py b/awx/main/apps.py index b45b3c20f2..3f7704f2e6 100644 --- a/awx/main/apps.py +++ b/awx/main/apps.py @@ -1,8 +1,17 @@ from django.apps import AppConfig +from django.db.models.signals import pre_migrate from django.utils.translation import ugettext_lazy as _ +def raise_migration_flag(**kwargs): + from awx.main.tasks import set_migration_flag + set_migration_flag.delay() + + class MainConfig(AppConfig): name = 'awx.main' verbose_name = _('Main') + + def ready(self): + pre_migrate.connect(raise_migration_flag, sender=self) diff --git a/awx/main/middleware.py b/awx/main/middleware.py index b1a03c9a38..3f9c7de56d 100644 --- a/awx/main/middleware.py +++ b/awx/main/middleware.py @@ -18,6 +18,7 @@ from django.db import IntegrityError, connection from django.utils.functional import curry from django.shortcuts import get_object_or_404, redirect from django.apps import apps +from django.core.cache import cache from django.utils.deprecation import MiddlewareMixin from django.utils.translation import ugettext_lazy as _ from django.urls import reverse, resolve @@ -213,8 +214,11 @@ class URLModificationMiddleware(MiddlewareMixin): class MigrationRanCheckMiddleware(MiddlewareMixin): def process_request(self, request): - executor = MigrationExecutor(connection) - plan = executor.migration_plan(executor.loader.graph.leaf_nodes()) - if bool(plan) and \ - getattr(resolve(request.path), 'url_name', '') != 'migrations_notran': - return redirect(reverse("ui:migrations_notran")) + if cache.get('migration_in_progress', False): + executor = MigrationExecutor(connection) + plan = executor.migration_plan(executor.loader.graph.leaf_nodes()) + if not bool(plan): + logger.info('Detected that migration finished, migration page taken down.') + cache.delete('migration_in_progress') + elif getattr(resolve(request.path), 'url_name', '') != 'migrations_notran': + return redirect(reverse("ui:migrations_notran")) diff --git a/awx/main/tasks.py b/awx/main/tasks.py index 9b263f550d..7fabe6308d 100644 --- a/awx/main/tasks.py +++ b/awx/main/tasks.py @@ -263,6 +263,12 @@ def apply_cluster_membership_policies(): logger.debug('Cluster policy computation finished in {} seconds'.format(time.time() - started_compute)) +@task(queue='tower_broadcast_all', exchange_type='fanout') +def set_migration_flag(): + logger.debug('Received migration-in-progress signal, will serve redirect.') + cache.set('migration_in_progress', True) + + @task(queue='tower_broadcast_all', exchange_type='fanout') def handle_setting_changes(setting_keys): orig_len = len(setting_keys) From a0910eb6de3c4713199e73c43f003c48c2895f9f Mon Sep 17 00:00:00 2001 From: AlanCoding Date: Mon, 11 Nov 2019 23:11:27 -0500 Subject: [PATCH 2/2] Apply migration flag check to task manager --- awx/main/middleware.py | 17 ++++++----------- awx/main/scheduler/tasks.py | 4 ++++ awx/main/utils/db.py | 26 ++++++++++++++++++++++++++ 3 files changed, 36 insertions(+), 11 deletions(-) diff --git a/awx/main/middleware.py b/awx/main/middleware.py index 3f9c7de56d..147baf3ef8 100644 --- a/awx/main/middleware.py +++ b/awx/main/middleware.py @@ -13,18 +13,17 @@ import urllib.parse from django.conf import settings from django.contrib.auth.models import User from django.db.models.signals import post_save -from django.db.migrations.executor import MigrationExecutor -from django.db import IntegrityError, connection +from django.db import IntegrityError from django.utils.functional import curry from django.shortcuts import get_object_or_404, redirect from django.apps import apps -from django.core.cache import cache from django.utils.deprecation import MiddlewareMixin from django.utils.translation import ugettext_lazy as _ from django.urls import reverse, resolve from awx.main.models import ActivityStream from awx.main.utils.named_url_graph import generate_graph, GraphNode +from awx.main.utils.db import migration_in_progress_check_or_relase from awx.conf import fields, register @@ -214,11 +213,7 @@ class URLModificationMiddleware(MiddlewareMixin): class MigrationRanCheckMiddleware(MiddlewareMixin): def process_request(self, request): - if cache.get('migration_in_progress', False): - executor = MigrationExecutor(connection) - plan = executor.migration_plan(executor.loader.graph.leaf_nodes()) - if not bool(plan): - logger.info('Detected that migration finished, migration page taken down.') - cache.delete('migration_in_progress') - elif getattr(resolve(request.path), 'url_name', '') != 'migrations_notran': - return redirect(reverse("ui:migrations_notran")) + if migration_in_progress_check_or_relase(): + if getattr(resolve(request.path), 'url_name', '') == 'migrations_notran': + return + return redirect(reverse("ui:migrations_notran")) diff --git a/awx/main/scheduler/tasks.py b/awx/main/scheduler/tasks.py index c0d3dd842e..c695bd08e1 100644 --- a/awx/main/scheduler/tasks.py +++ b/awx/main/scheduler/tasks.py @@ -5,11 +5,15 @@ import logging # AWX from awx.main.scheduler import TaskManager from awx.main.dispatch.publish import task +from awx.main.utils.db import migration_in_progress_check_or_relase logger = logging.getLogger('awx.main.scheduler') @task() def run_task_manager(): + if migration_in_progress_check_or_relase(): + logger.debug("Not running task manager because migration is in progress.") + return logger.debug("Running Tower task manager.") TaskManager().schedule() diff --git a/awx/main/utils/db.py b/awx/main/utils/db.py index f91f2d7b65..88e08ad55f 100644 --- a/awx/main/utils/db.py +++ b/awx/main/utils/db.py @@ -1,8 +1,16 @@ # Copyright (c) 2017 Ansible by Red Hat # All Rights Reserved. +import logging from itertools import chain +from django.core.cache import cache +from django.db.migrations.executor import MigrationExecutor +from django.db import connection + + +logger = logging.getLogger('awx.main.utils.db') + def get_all_field_names(model): # Implements compatibility with _meta.get_all_field_names @@ -14,3 +22,21 @@ def get_all_field_names(model): # GenericForeignKey from the results. if not (field.many_to_one and field.related_model is None) ))) + + +def migration_in_progress_check_or_relase(): + '''A memcache flag is raised (set to True) to inform cluster + that a migration is ongoing see main.apps.MainConfig.ready + if the flag is True then the flag is removed on this instance if + models-db consistency is observed + effective value of migration flag is returned + ''' + migration_in_progress = cache.get('migration_in_progress', False) + if migration_in_progress: + executor = MigrationExecutor(connection) + plan = executor.migration_plan(executor.loader.graph.leaf_nodes()) + if not bool(plan): + logger.info('Detected that migration finished, migration flag taken down.') + cache.delete('migration_in_progress') + migration_in_progress = False + return migration_in_progress