Update release check to use django-redis

This commit is contained in:
jeremystretch 2021-07-07 20:57:47 -04:00
parent d9e27b6a82
commit 2c023ef7a0
3 changed files with 17 additions and 60 deletions

View File

@ -1,7 +1,7 @@
import logging import logging
from cacheops import CacheMiss, cache
from django.conf import settings from django.conf import settings
from django.core.cache import cache
from django_rq import get_queue from django_rq import get_queue
from utilities.background_tasks import get_releases from utilities.background_tasks import get_releases
@ -12,12 +12,11 @@ logger = logging.getLogger('netbox.releases')
def get_latest_release(pre_releases=False): def get_latest_release(pre_releases=False):
if settings.RELEASE_CHECK_URL: if settings.RELEASE_CHECK_URL:
logger.debug("Checking for most recent release") logger.debug("Checking for most recent release")
try: latest_release = cache.get('latest_release')
latest_release = cache.get('latest_release') if latest_release:
if latest_release: logger.debug(f"Found cached release: {latest_release}")
logger.debug("Found cached release: {}".format(latest_release)) return latest_release
return latest_release else:
except CacheMiss:
# Check for an existing job. This can happen if the RQ worker process is not running. # Check for an existing job. This can happen if the RQ worker process is not running.
queue = get_queue('check_releases') queue = get_queue('check_releases')
if queue.jobs: if queue.jobs:

View File

@ -3,8 +3,8 @@ from logging import ERROR
from unittest.mock import Mock, patch from unittest.mock import Mock, patch
import requests import requests
from cacheops import CacheMiss, RedisCache
from django.conf import settings from django.conf import settings
from django.core.cache import cache
from django.test import SimpleTestCase, override_settings from django.test import SimpleTestCase, override_settings
from packaging.version import Version from packaging.version import Version
from requests import Response from requests import Response
@ -60,10 +60,8 @@ def unsuccessful_github_response(url, *_args, **_kwargs):
@override_settings(RELEASE_CHECK_URL='https://localhost/unittest/releases', RELEASE_CHECK_TIMEOUT=160876) @override_settings(RELEASE_CHECK_URL='https://localhost/unittest/releases', RELEASE_CHECK_TIMEOUT=160876)
class GetReleasesTestCase(SimpleTestCase): class GetReleasesTestCase(SimpleTestCase):
@patch.object(requests, 'get') @patch.object(requests, 'get')
@patch.object(RedisCache, 'set') @patch.object(cache, 'set')
@patch.object(RedisCache, 'get') def test_pre_releases(self, dummy_cache_set: Mock, dummy_request_get: Mock):
def test_pre_releases(self, dummy_cache_get: Mock, dummy_cache_set: Mock, dummy_request_get: Mock):
dummy_cache_get.side_effect = CacheMiss()
dummy_request_get.side_effect = successful_github_response dummy_request_get.side_effect = successful_github_response
releases = get_releases(pre_releases=True) releases = get_releases(pre_releases=True)
@ -90,10 +88,8 @@ class GetReleasesTestCase(SimpleTestCase):
) )
@patch.object(requests, 'get') @patch.object(requests, 'get')
@patch.object(RedisCache, 'set') @patch.object(cache, 'set')
@patch.object(RedisCache, 'get') def test_no_pre_releases(self, dummy_cache_set: Mock, dummy_request_get: Mock):
def test_no_pre_releases(self, dummy_cache_get: Mock, dummy_cache_set: Mock, dummy_request_get: Mock):
dummy_cache_get.side_effect = CacheMiss()
dummy_request_get.side_effect = successful_github_response dummy_request_get.side_effect = successful_github_response
releases = get_releases(pre_releases=False) releases = get_releases(pre_releases=False)
@ -119,10 +115,7 @@ class GetReleasesTestCase(SimpleTestCase):
) )
@patch.object(requests, 'get') @patch.object(requests, 'get')
@patch.object(RedisCache, 'set') def test_failed_request(self, dummy_request_get: Mock):
@patch.object(RedisCache, 'get')
def test_failed_request(self, dummy_cache_get: Mock, dummy_cache_set: Mock, dummy_request_get: Mock):
dummy_cache_get.side_effect = CacheMiss()
dummy_request_get.side_effect = unsuccessful_github_response dummy_request_get.side_effect = unsuccessful_github_response
with self.assertLogs(level=ERROR) as cm: with self.assertLogs(level=ERROR) as cm:
@ -143,28 +136,3 @@ class GetReleasesTestCase(SimpleTestCase):
headers={'Accept': 'application/vnd.github.v3+json'}, headers={'Accept': 'application/vnd.github.v3+json'},
proxies=settings.HTTP_PROXIES proxies=settings.HTTP_PROXIES
) )
# Check if failure is put in cache
dummy_cache_set.assert_called_once_with(
'latest_release_no_retry',
'https://localhost/unittest/releases',
900
)
@patch.object(requests, 'get')
@patch.object(RedisCache, 'set')
@patch.object(RedisCache, 'get')
def test_blocked_retry(self, dummy_cache_get: Mock, dummy_cache_set: Mock, dummy_request_get: Mock):
dummy_cache_get.return_value = 'https://localhost/unittest/releases'
dummy_request_get.side_effect = successful_github_response
releases = get_releases()
# Check result
self.assertListEqual(releases, [])
# Check if request is NOT made
dummy_request_get.assert_not_called()
# Check if cache is not updated
dummy_cache_set.assert_not_called()

View File

@ -1,8 +1,8 @@
import logging import logging
import requests import requests
from cacheops.simple import cache, CacheMiss
from django.conf import settings from django.conf import settings
from django.core.cache import cache
from django_rq import job from django_rq import job
from packaging import version from packaging import version
@ -18,16 +18,8 @@ def get_releases(pre_releases=False):
} }
releases = [] releases = []
# Check whether this URL has failed recently and shouldn't be retried yet
try: try:
if url == cache.get('latest_release_no_retry'): logger.info(f"Fetching new releases from {url}")
logger.info("Skipping release check; URL failed recently: {}".format(url))
return []
except CacheMiss:
pass
try:
logger.debug("Fetching new releases from {}".format(url))
response = requests.get(url, headers=headers, proxies=settings.HTTP_PROXIES) response = requests.get(url, headers=headers, proxies=settings.HTTP_PROXIES)
response.raise_for_status() response.raise_for_status()
total_releases = len(response.json()) total_releases = len(response.json())
@ -38,12 +30,10 @@ def get_releases(pre_releases=False):
if not pre_releases and (release.get('devrelease') or release.get('prerelease')): if not pre_releases and (release.get('devrelease') or release.get('prerelease')):
continue continue
releases.append((version.parse(release['tag_name']), release.get('html_url'))) releases.append((version.parse(release['tag_name']), release.get('html_url')))
logger.debug("Found {} releases; {} usable".format(total_releases, len(releases))) logger.debug(f"Found {total_releases} releases; {len(releases)} usable")
except requests.exceptions.RequestException: except requests.exceptions.RequestException as exc:
# The request failed. Set a flag in the cache to disable future checks to this URL for 15 minutes. logger.exception(f"Error while fetching latest release from {url}: {exc}")
logger.exception("Error while fetching {}. Disabling checks for 15 minutes.".format(url))
cache.set('latest_release_no_retry', url, 900)
return [] return []
# Cache the most recent release # Cache the most recent release