2012-05-16 2 views
18

플라스크 앱을 닫거나 DB 연결을 다시 사용할 수없는 것으로 보입니다. 내 테스트 스위트가 20 (postgresql.confmax_connections 설정)에 도달 할 때까지 열려있는 연결의 수는 올라 실행되면 그때 내가 볼, PostgreSQL의 9.1.3 및어떻게 플라스크 SQLAlchemy 재사용 DB 연결을 만들 수 있습니까?

Flask==0.8 
Flask-SQLAlchemy==0.16 
psycopg2==2.4.5 

을 사용하고 있습니다 :

OperationalError: (OperationalError) FATAL: sorry, too many clients already 
None None 

나는 코드를 create_alldrop_all이라고 부르는 지점으로 줄였습니다 (그러나 모델이 없으므로 sql을 발행하지 않습니다).

나는 연결이 로그와 체크 아웃되고 참조 : 각 시험

DEBUG:sqlalchemy.pool.QueuePool:Connection <connection object at 0x101c1dff0; dsn: 'dbname=cx_test host=localhost', closed: 0> checked out from pool 
DEBUG:sqlalchemy.pool.QueuePool:Connection <connection object at 0x101c1dff0; dsn: 'dbname=cx_test host=localhost', closed: 0> being returned to pool 
WARNING:root:impl <-------- That's the test running 
DEBUG:sqlalchemy.pool.QueuePool:Connection <connection object at 0x101c1dff0; dsn: 'dbname=cx_test host=localhost', closed: 0> checked out from pool 
DEBUG:sqlalchemy.pool.QueuePool:Connection <connection object at 0x101c1dff0; dsn: 'dbname=cx_test host=localhost', closed: 0> being returned to pool 

연결의 주소 (부분 "XYZ에서 연결 개체를")를 실행 다르다. 나는 이것이 문제와 관련이 있다고 생각하지만, 더 자세히 조사 할 방법을 모르겠습니다.

from flask import Flask 
from flask.ext.sqlalchemy import SQLAlchemy 
from unittest import TestCase 

import logging 
logging.basicConfig(level=logging.DEBUG) 
logging.getLogger('sqlalchemy.pool').setLevel(logging.DEBUG) 
logging.getLogger('sqlalchemy.engine').setLevel(logging.DEBUG) 
logging.getLogger('sqlalchemy.dialects').setLevel(logging.DEBUG) 
logging.getLogger('sqlalchemy.orm').setLevel(logging.DEBUG) 


db = SQLAlchemy() 

def create_app(config=None): 
    app = Flask(__name__) 
    app.config.from_object(config) 
    db.init_app(app) 
    return app 


class AppTestCase(TestCase): 
    SQLALCHEMY_DATABASE_URI = "postgresql://localhost/cx_test" 
    TESTING = True 

    def create_app(self): 
     return create_app(self) 

    def setUp(self): 
     self.app = self.create_app() 
     self.client = self.app.test_client() 
     self._ctx = self.app.test_request_context() 
     self._ctx.push() 
     db.create_all() 

    def tearDown(self): 
     db.session.remove() 
     db.drop_all() 
     self._ctx.pop() 


class TestModel(AppTestCase): 
    def impl(self): 
     logging.warn("impl") 
     pass 

    def test_01(self): 
     self.impl() 

    def test_02(self): 
     self.impl() 

    def test_03(self): 
     self.impl() 

    def test_04(self): 
     self.impl() 

    def test_05(self): 
     self.impl() 

    def test_06(self): 
     self.impl() 

    def test_07(self): 
     self.impl() 

    def test_08(self): 
     self.impl() 

    def test_09(self): 
     self.impl() 

    def test_10(self): 
     self.impl() 

    def test_11(self): 
     self.impl() 

    def test_12(self): 
     self.impl() 

    def test_13(self): 
     self.impl() 

    def test_14(self): 
     self.impl() 

    def test_15(self): 
     self.impl() 

    def test_16(self): 
     self.impl() 

    def test_17(self): 
     self.impl() 

    def test_18(self): 
     self.impl() 

    def test_19(self): 
     self.impl() 



if __name__ == "__main__": 
    import unittest 
    unittest.main() 

이 내가 플라스크에 응용 공장을 처음 사용하고, 나는 Flask-SQLAlchemy docs에서 부분적으로이 코드를 복사 :

는 아래의 코드는 새로운 venv에 문제가 재생하기. Elseware 그 문서에서는 잘못된 컨텍스트에서 db를 사용하면 연결이 누출 될 수 있다고 언급합니다. 아마도 init을 잘못 수행하고 있습니까?

답변

10

SQLAlchemy 문서를 읽은 후 db 인스턴스를 사용하여 결국 해결책을 얻었습니다.

플라스크-SQLAlchemy의 가장 최신 버전의
def tearDown(self): 
    db.session.remove() 
    db.drop_all() 
    db.get_engine(self.app).dispose() 
    self._ctx.pop() 
1

test method 전후에 setUp and tearDown이 호출됨을 알고 있습니다. 코드에서 비어있는 데이터베이스를 보장하기 위해 필요로하는 것처럼 보입니다.
그러나 각 테스트 클래스마다 한 번 호출되는 setUpClass and tearDownClass도 있습니다.
test-method 관련 부분을 유지하면서 현재 가지고있는 코드를 분리하고 db-connection 관련 부분을 Class 레벨로 이동할 수 있습니다.

+1

감사합니다 Van -이 문제는 테스트 스위트에서 해결되지만 더 적은 연결이 누출된다는 의미가 아닙니까? –

+0

@TomDunham : 네 말이 맞을 것 같아. '포스트그레스 '가 없으니 죄송합니다. – van

6

1 년 전에 질문이 제기되었으므로, OP가 자신의 문제를 해결했는지 확인해야합니다. 그러나 무엇이 진행될지를 알기 위해 여기로 방황 한 사람은 누구나 최선의 설명을 드리겠습니다.

van이 말했듯이 문제는 각 테스트에 대해 setUptearDown을 호출하는 테스트 사례에서 비롯된 것입니다. 연결이 SQLAlchemy에서 정확히 유출되지는 않지만 대신 각 테스트에 자체 setUp이 있기 때문에 여러 응용 프로그램 인스턴스가 만들어집니다. 각 응용 프로그램에는 고유 한 데이터베이스 연결 풀이 있으며 이는 다시 사용되거나 재활용되지 않습니다 테스트가 끝나면 즉

는 연결이 체크 아웃 풀 제대로로 돌아 있지만 연결은 다음 같은 응용 프로그램 (연결 풀링의 포인트) 내에서 향후 거래에 대한 유휴 연결로 살고되고있다.

위의 테스트 사례에서 약 20 개의 연결 풀 (각각 create/drop_all로 인해 유휴 연결이 있음)이 만들어지고 포스트 그레스 연결 제한을 점유합니다.