Merge pull request #4210 from alphagov/paas-redis-migration-181796569

Prepare to switch to Redis on PaaS
This commit is contained in:
Ben Thorner
2022-04-13 11:53:30 +01:00
committed by GitHub
3 changed files with 50 additions and 2 deletions

View File

@@ -8,6 +8,12 @@ import os
def extract_cloudfoundry_config():
vcap_services = json.loads(os.environ['VCAP_SERVICES'])
# Redis config
if 'redis' in vcap_services:
os.environ['REDIS_URL'] = vcap_services['redis'][0]['credentials']['uri']
vcap_application = json.loads(os.environ.get('VCAP_APPLICATION'))
os.environ['NOTIFY_ENVIRONMENT'] = vcap_application['space_name']
os.environ['NOTIFY_LOG_PATH'] = '/home/vcap/logs/app.log'

View File

@@ -1,6 +1,8 @@
import os
import sys
import traceback
import eventlet
import socket
import gunicorn
from gds_metrics.gunicorn import child_exit # noqa
@@ -17,3 +19,21 @@ def worker_abort(worker):
worker.log.info("worker received ABORT")
for stack in sys._current_frames().values():
worker.log.error(''.join(traceback.format_stack(stack)))
def fix_ssl_monkeypatching():
"""
eventlet works by monkey-patching core IO libraries (such as ssl) to be non-blocking. However, there's currently
a bug: In the normal socket library it may throw a timeout error as a `socket.timeout` exception. However
eventlet.green.ssl's patch raises an ssl.SSLError('timed out',) instead. redispy handles socket.timeout but not
ssl.SSLError, so we solve this by monkey patching the monkey patching code to raise the correct exception type
:scream:
https://github.com/eventlet/eventlet/issues/692
"""
# this has probably already been called somewhere in gunicorn internals, however, to be sure, we invoke it again.
# eventlet.monkey_patch can be called multiple times without issue
eventlet.monkey_patch()
eventlet.green.ssl.timeout_exc = socket.timeout
fix_ssl_monkeypatching()

View File

@@ -1,3 +1,4 @@
import json
import os
import pytest
@@ -6,12 +7,33 @@ from app.cloudfoundry_config import extract_cloudfoundry_config
@pytest.fixture
def cloudfoundry_environ(os_environ):
def cloudfoundry_config():
return {
'redis': [{
'credentials': {
'uri': 'redis uri'
}
}],
}
@pytest.fixture
def vcap_application(os_environ):
os.environ['VCAP_APPLICATION'] = '{"space_name":"🚀🌌"}'
def test_extract_cloudfoundry_config_populates_other_vars(cloudfoundry_environ):
def test_extract_cloudfoundry_config_populates_other_vars(vcap_application, cloudfoundry_config):
os.environ['VCAP_SERVICES'] = json.dumps(cloudfoundry_config)
extract_cloudfoundry_config()
assert os.environ['REDIS_URL'] == 'redis uri'
assert os.environ['NOTIFY_ENVIRONMENT'] == '🚀🌌'
assert os.environ['NOTIFY_LOG_PATH'] == '/home/vcap/logs/app.log'
def test_set_config_env_vars_copes_if_redis_not_set(vcap_application, cloudfoundry_config):
del cloudfoundry_config['redis']
os.environ['VCAP_SERVICES'] = json.dumps(cloudfoundry_config)
extract_cloudfoundry_config()
assert 'REDIS_URL' not in os.environ