Как выбрать Config на основе серверной переменной во Flask?

Я бегу nginx + gunicorn + колбу

Мой конфиг nginx выглядит так:

...

        proxy_set_header            X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header            Host $http_host;
        proxy_set_header            Stage "development";

        proxy_redirect off;

...

Мое приложение для колб выглядит так:

from flask import Flask, request

from werkzeug.contrib.fixers import ProxyFix

app = Flask(__name__)

# configuration settings

if request.headers.get('Stage') == 'production':
    app.config.from_object('config.production_config')
else:
    app.config.from_object('config.development_config')

@app.route('/')
def index():
    return "hello"

app.wsgi_app = ProxyFix(app.wsgi_app)

Тем не мение,

Это не похоже на работу.

Я получаю: RuntimeError: работает вне контекста запроса

Мой nginx настроен так, чтобы у меня была среда разработки / производства, но я хочу сказать, что это "расположение сервера" является средой разработки, и я хочу, чтобы Flask использовал соответствующую конфигурацию.

2 ответа

Решение

Конфигурация приложения предназначена для всего приложения, а заголовки запросов - только для одного запроса. Одно и то же приложение обычно обрабатывает много запросов. Поэтому вы не можете установить конфигурацию на основе заголовков запросов.

Ваш код на уровне модуля выполняется при запуске сервера, когда еще не поступило ни одного запроса, поскольку приложение еще не поступило. Это то, что означает сообщение "работа вне контекста запроса".

То, что вы пытаетесь сделать (prod vs. dev config), лучше всего сделать с помощью переменной окружения в скрипте, запускающем ваш сервер gunicorn. Если вы хотите использовать оба одновременно, проще всего запустить два сервера gunicorn.

В качестве альтернативы создайте два объекта приложения, запустите их оба в одном и том же процессе и отправьте с промежуточным программным обеспечением WSGI, похожим на следующее: http://flask.pocoo.org/docs/patterns/appdispatch/

Это немного устарело, но я хотел бы добавить, как мы делаем это с помощью колбы. Большая часть этого адаптирована с http://flask.pocoo.org/docs/config/.

В нашем config.py мы определяем несколько классов (по одному на среду):

class Config(object):
    FOO = 1
    BAR = 2

class Development(Config):
    BAR = 3

Затем в каждом из наших узлов приложения мы устанавливаем переменную окружения в сценариях инициализации gunicorn (для нас это живет в конфигурации супервизора, но это не обязательно).

APPLICATION_ENV='Development'

Затем в приложении-колбе во время инициализации (запускается только при запуске сервера, а не в контексте запроса):

try:
    env = os.environ['APPLICATION_ENV']
except KeyError as e:
    logging.error('Unknown environment key, defaulting to Development')
    env = 'Development'
    app.config.from_object('config.%s' % env)

теперь app.config['BAR'] будет 3.

Мы также хотели поддерживать локальные конфигурационные файлы (например, на компьютере разработчика или пароли, которые развертываются непосредственно от chef на машине и не хранятся в git). Для этого мы расширили вышеприведенное, чтобы также загрузить локальную конфигурацию на основе параметра app.config['LOCAL_CONFIG'].

class Development(Config):
    BAR = 3
    LOCAL_CONFIG = '/etc/localConfig.py'

А затем в /etc/localConfig.py

BAR = 4

И снова в нашем коде инициализации приложения после кода выше загружается исходный app.config для среды:

if 'LOCAL_CONFIG' in app.config:
    #try to load the local configuration overrides
    if app.config.from_pyfile(app.config['LOCAL_CONFIG'], silent=True):
        logging.info('Loaded local config file at %s' % app.config['LOCAL_CONFIG'])
    else:
        logging.warning('Failed to load local config file at %s - does it exist?' % app.config['LOCAL_CONFIG'])

На данный момент app.config['BAR'] равно 4.

Это не идеально, потому что если в вашей конфигурации есть dict, вы сможете переопределить только весь dict, а не ключи внутри него. Это действительно выполняет большую часть того, что нам нужно.

Другие вопросы по тегам