API запущен, db убит, db запущен, peewee.InterfaceError соединение уже закрыто

Запустить app.py, затем убить базу данных и нажать /api/foo дает мне:

peewee.OperationalError: не удалось подключиться к серверу: соединение отклонено

Восстановление базы данных дает мне и удар /api/foo дает мне:

peewee.OperationalError: разрыв соединения из-за команды администратора \nSSL соединение было неожиданно закрыто \ n

И удар /api/foo снова дает мне:

peewee.InterfaceError: соединение уже закрыто

Прецедент

test_case/__init__.py

#!/usr/bin/env python

from os import environ

from bottle import Bottle, request, response
from playhouse.db_url import connect

bottle_api = Bottle()
db = connect(environ['RDBMS_URI'])

from test_case.foo.models import Foo

db.connect()  # Not needed, but do want to throw errors ASAP
db.create_tables([Foo], safe=True)  # Create tables (if they don't exist)

from test_case.foo.routes import foo_api

bottle_api.merge(foo_api)

bottle_api.catchall = False


@bottle_api.hook('before_request')
def _connect_db():
    print 'Connecting to db'
    db.connect()


@bottle_api.hook('after_request')
def _close_db():
    print 'Closing db'
    if not db.is_closed():
        db.close()


def error_catcher(environment, start_response):
    try:
        return bottle_api.wsgi(environment, start_response)
    except Exception as e:
        environment['PATH_INFO'] = '/api/error'
        environment['api_error'] = e
        return bottle_api.wsgi(environment, start_response)


@bottle_api.route('/api/error')
def global_error():
    response.status = 500
    return {'error': (lambda res: res[res.find("'") + 1:res.rfind("'")])(
                      str(request.environ['api_error'].__class__)),
            'error_message': request.environ['api_error'].message}

test_case/__main__.py

from __init__ import bottle_api
# Or `from __init__ import bottle_api`; `from bottle import run`;
# Then `run(error_catcher, port=5555)`

bottle_api.run(port=5555)

test_case/foo/__init__.py

test_case/foo/models.py

from peewee import Model, CharField

from test_case import db

class Foo(Model):
    id = CharField(primary_key=True)

    class Meta(object):
        database = db

test_case/foo/routes.py

from bottle import Bottle
from playhouse.shortcuts import model_to_dict

from test_case.foo.models import Foo

foo_api = Bottle()


@foo_api.get('/api/foo')
def retrieve_foos():
    return {'foos': tuple(model_to_dict(foo) for foo in Foo.select())}

Github Gist для легкого клонирования.

1 ответ

Обновить:

Я полагаю, что проблема заключается в том, как вы структурировали свой импорт и как Python загружает и кэширует модули в sys.path.

Я думаю, что один из ваших модулей импортируется и загружается дважды, и разные части кодовой базы используют разные экземпляры модуля.

Таким образом, представления в foo.routes используют один экземпляр объекта базы данных, в то время как перехватчики соединения используют другой.

Вместо from __init__что насчет попыток from test_case import bottle_api? Это единственное утверждение импорта, которое выпадает на меня как возможный преступник.


Я добавил следующее в ваш код, чтобы запустить его из командной строки:

if __name__ == '__main__':
    api.run()

Затем я сделал запрос /api/foo и увидел некоторые поддельные данные. Я остановил сервер Postgresql и получил эту ошибку:

Traceback (most recent call last):
  File "/usr/lib64/python2.7/wsgiref/handlers.py", line 85, in run
    self.result = application(self.environ, self.start_response)
  File "/home/charles/tmp/scrap/bottlez/lib/python2.7/site-packages/bottle.py", line 979, in __call__
    return self.wsgi(environ, start_response)
  File "/home/charles/tmp/scrap/bottlez/lib/python2.7/site-packages/bottle.py", line 954, in wsgi
    out = self._cast(self._handle(environ))
  File "/home/charles/tmp/scrap/bottlez/lib/python2.7/site-packages/bottle.py", line 857, in _handle
    self.trigger_hook('before_request')
  File "/home/charles/tmp/scrap/bottlez/lib/python2.7/site-packages/bottle.py", line 640, in trigger_hook
    return [hook(*args, **kwargs) for hook in self._hooks[__name][:]]
  File "bt.py", line 31, in _connect_db
    db.connect()
  File "/home/charles/tmp/scrap/bottlez/src/peewee/peewee.py", line 2967, in connect
    self.initialize_connection(self.__local.conn)
  File "/home/charles/tmp/scrap/bottlez/src/peewee/peewee.py", line 2885, in __exit__
    reraise(new_type, new_type(*exc_value.args), traceback)
  File "/home/charles/tmp/scrap/bottlez/src/peewee/peewee.py", line 2965, in connect
    **self.connect_kwargs)
  File "/home/charles/tmp/scrap/bottlez/src/peewee/peewee.py", line 3279, in _connect
    conn = psycopg2.connect(database=database, **kwargs)
  File "/home/charles/tmp/scrap/bottlez/lib/python2.7/site-packages/psycopg2/__init__.py", line 164, in connect
    conn = _connect(dsn, connection_factory=connection_factory, async=async)
OperationalError: could not connect to server: Connection refused
    Is the server running on host "localhost" (::1) and accepting
    TCP/IP connections on port 5432?
could not connect to server: Connection refused
    Is the server running on host "localhost" (127.0.0.1) and accepting
    TCP/IP connections on port 5432?

Когда я перезапустил сервер и сделал следующий запрос, я получил нормальный ответ с моими тестовыми данными.

Короче говоря, я не уверен, что мне не хватает, но мне кажется, что код работает правильно.

Postgresql 9.4, psycopg2 2.6, python 2.7.9, peewee 2.6.0

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