2012-05-16 17 views
18

DB bağlantılarımı kapatmak veya yeniden kullanmak için Flask uygulamasına gidemiyorum. Benim test paketi 20 (postgresql.conf içinde max_connections ayar) vurur kadar açık bağlantı sayısı tırmanıyor çalışır gibi ben o zaman anladım, PostgreSQL 9.1.3 veFlask SQLAlchemy'ı db bağlantılarını nasıl yeniden kullanırım?

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

kullanıyorum:

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

Kodu sadece create_all ve drop_all (ancak model olmadığı için herhangi bir sql yayınlamadığı) noktasını düşürdüm.

Ben bağlantıları günlüklerinde ve teslim edilen bkz: Her test için

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 

bağlantının adresi (kesiminde "xyz de bağlantı nesnesi") çalıştırın farklıdır. Bunun sorununla ilgili bir şey olduğundan şüpheleniyorum, ama daha fazla nasıl araştırılacağından emin değilim.

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() 

Bu benim şişeye uygulama fabrikaları ilk kez kullanıyorsanız, ve ben Flask-SQLAlchemy docs den kısmen bu kodu kopyalanan:

kod altında yeni venv sorunu yeniden üretir. Elseware Bu dokümanlar, yanlış bağlamda bir db kullanılmasının sızıntıya neden olacağından bahsetmektedir - belki yanlış bir şekilde init yapıyorum?

cevap

10

SQLAlchemy belgelerini okuduktan ve db örneğiyle uğraştıktan sonra sonunda çözüm buldum.

Flask-sqlalchemy en son sürümlerinde
def tearDown(self): 
    db.session.remove() 
    db.drop_all() 
    db.get_engine(self.app).dispose() 
    self._ctx.pop() 
1

setUp and tearDown'un her test method'dan önce ve sonra çağrıldığını biliyorsunuz. Kodunuzdan boş veritabanını sağlamak için onlara ihtiyacınız var gibi görünüyor. Bununla birlikte, her test sınıfı için bir kez çağrılan setUpClass and tearDownClass da vardır.
Şu anda sahip olduğunuz kodu bölebileceğinizi ve Class-düzeyine ilişkin db-connection ilgili bölümünü taşıyabileceğinizi ve test-method ilgili bölümün nerede olması gerektiği ile ilgili olarak tuttuğuna inanıyorum.

+1

Teşekkürler Van - bu problemi test paketiyle çözüyor, ancak sadece daha az bağlantı sızdırıyor olduğumu mu göstermiyor? –

+0

@TomDunham: Sanırım haklısın. 'postgres' yok, o yüzden sana yardım edemem, üzgünüm .. – van

6

Bir yıl önce sorular sorulduğundan, OP'nin sorunlarını çözmüş olması gerektiğini düşünüyorum. Ama için, burada benim en iyi açıklama ne oluyor anlamaya çalışıyorum (benim gibi) Buraya kadar dolaştım kim: van söylediği gibi

, sorun her test için setUp ve tearDown arayarak test durumu ile gerçekten de öyle. Bağlantı, SQLAlchemy'den tam olarak sızmasa da, bunun yerine, her bir testin kendi setUp'a sahip olması nedeniyle, uygulamanın birden çok örneği oluşturulur: her uygulama, muhtemelen yeniden kullanılmayan veya geri dönüştürülmemiş olan kendi veritabanı bağlantı havuzuna sahip olacaktır. Test bittiğinde. Başka bir deyişle

, bağlantı teslim ve havuz doğru döndü ama bağlantı daha sonra aynı app (bağlantı havuzu noktası) içinde gelecekteki işlemler için boş bağlantı olarak yaşamaya ediliyor.

Yukarıdaki test örneğinde, yaklaşık 20 bağlantı havuzu (her biri oluşturma/bırakma nedeniyle boş bağlantıya sahip) oluşturulur ve postgres bağlantı sınırını işgal eder.

İlgili konular