Записки программиста, обо всем и ни о чем. Но, наверное, больше профессионального.

2013-04-18

Flask & DB connections

Всем известно, что веб-приложение может отрабатывать сотни запросов в секунду. Известно, также, что приличное веб-приложение обращается к базе данных при ответах на запрос. Очевидно, что для такого веб-приложения было бы разумно установить соединение с БД один раз, при запуске, к примеру, и пользоваться этим коннектом во всех запросах.

Однако, архитекторы Flask так не думают. Упирая на многопоточность веб-приложения как на ключевую характеристику Flask, они предлагают нам открывать соединение с БД при входе в «контекст» приложения. При этом, к тому же, происходит подмена понятий. Во Flask контекст приложения, не смотря на название, создается для отработки текущего запроса, после чего уничтожается. Соответственно, открытие/закрытие коннекта к БД происходит, возможно, сотни раз в секунду. Дикость. Недовольным рекомендуют обращаться к расширению Flask-SqlAlchemy, которое поддерживает пулы соединений с БД.

Я не хочу в своем микроприложении использовать макрофреймворк типа SQLAlchemy. Но и открывать/закрывать коннекты к БД на каждый чих мне религия не позволяет. Поэтому я почитал код Flask-sqlalchemy и выдрал оттуда механизм хранения.
Получился Flask extension или плагин, называйте как хотите
Позволяет сохранять данные, коннект к БД, например, на протяжении жизни всего приложения, суть головного процесса.
#!/usr/bin/env python
# -*- mode: python; coding: utf-8 -*-
# (c) Valik mailto:vasnake@gmail.com
r""" Global storage Flask extension.
In Flask, it's possible to store data across many requests.
But you must be aware of threading issues in that case.
Thanks to flask_sqlalchemy
https://github.com/mitsuhiko/flask-sqlalchemy/blob/master/flask_sqlalchemy.py
usage:
APP = Flask(__name__)
GS = flask_gs.VGlobalStorage(APP)
...
def getDataSource():
conn = GS.getData('PGCONN') # Psycopg connection is thread-safe http://initd.org/psycopg/docs/usage.html#thread-safety
if not conn:
dsn = config.get('PGDSN')
conn = postgis.PGConnection(dsn)
GS.setData('PGCONN', conn)
return conn
"""
from threading import Lock
try:
from flask import _app_ctx_stack as stack
except ImportError:
from flask import _request_ctx_stack as stack
EXTNAME = 'vglobalstorage'
class _VStorage(object):
""" Storage dictionary
"""
def __init__(self, app):
self.app = app
self.data = {}
class VGlobalStorage(object):
""" Flask extension
"""
def __init__(self, app=None):
self._storage_lock = Lock()
self.app = None
if app is not None:
self.app = app
self.init_app(self.app)
def init_app(self, app):
""" Called from constructor, Flask need this.
:param app: Flask app
:type app: flask.Flask()
"""
if not hasattr(app, 'extensions'):
app.extensions = {}
app.extensions[EXTNAME] = _VStorage(app)
def getData(self, key):
""" Getter, get stored data by key.
:param key: any existed key for dictionary
:type key: object
"""
return self._get_data(self.get_app(), key)
def setData(self, key, val):
""" Setter, store data in dictionary.
:param key: any key for dictionary
:type key: object
:param val: any value
:type val: object
"""
return self._set_data(self.get_app(), key, val)
def _get_data(self, app, key):
""" Internal getter.
:param app: flask app
:type app: flask.Flask()
:param key: any dictionary key
:type key: object
"""
with self._storage_lock:
stor = get_storage(app)
return stor.data.get(key, None)
def _set_data(self, app, key, val):
""" Internal setter.
:param app: flask app
:type app: flask.Flask()
:param key: any dictionary key
:type key: object
:param val: any value
:type val: object
"""
with self._storage_lock:
stor = get_storage(app)
stor.data[key] = val
def get_app(self, reference_app=None):
""" Return actual app object
:param reference_app: flask app
:type reference_app: flask.Flask()
"""
if reference_app is not None:
return reference_app
if self.app is not None:
return self.app
ctx = stack.top
if ctx is not None:
return ctx.app
raise RuntimeError('application not registered on gs '
'instance and no application bound to current context')
#class VGlobalStorage(object):
def get_storage(app):
""" Return storage object
:param app: flask app
:type app: flask.Flask()
"""
return app.extensions[EXTNAME]
view raw flask_gs.py hosted with ❤ by GitHub

Вполне возможно я что-то упустил. Но на текущий момент практика показывает, что модуль работает нормально. Разве что не надо забывать, что хранить в таком хранилище стоит только thread-safe данные.

Что почитать по теме


original post http://vasnake.blogspot.com/2013/04/flask-db-connections.html

Комментариев нет:

Отправить комментарий

Архив блога

Ярлыки

linux (241) python (191) citation (186) web-develop (170) gov.ru (159) video (124) бытовуха (115) sysadm (100) GIS (97) Zope(Plone) (88) бурчалки (84) Book (83) programming (82) грабли (77) Fun (76) development (73) windsurfing (72) Microsoft (64) hiload (62) internet provider (57) opensource (57) security (57) опыт (55) movie (52) Wisdom (51) ML (47) driving (45) hardware (45) language (45) money (42) JS (41) curse (40) bigdata (39) DBMS (38) ArcGIS (34) history (31) PDA (30) howto (30) holyday (29) Google (27) Oracle (27) tourism (27) virtbox (27) health (26) vacation (24) AI (23) Autodesk (23) SQL (23) humor (23) Java (22) knowledge (22) translate (20) CSS (19) cheatsheet (19) hack (19) Apache (16) Klaipeda (15) Manager (15) web-browser (15) Никонов (15) functional programming (14) happiness (14) music (14) todo (14) PHP (13) course (13) scala (13) weapon (13) HTTP. Apache (12) SSH (12) frameworks (12) hero (12) im (12) settings (12) HTML (11) SciTE (11) USA (11) crypto (11) game (11) map (11) HTTPD (9) ODF (9) Photo (9) купи/продай (9) benchmark (8) documentation (8) 3D (7) CS (7) DNS (7) NoSQL (7) cloud (7) django (7) gun (7) matroska (7) telephony (7) Microsoft Office (6) VCS (6) bluetooth (6) pidgin (6) proxy (6) Donald Knuth (5) ETL (5) NVIDIA (5) Palanga (5) REST (5) bash (5) flash (5) keyboard (5) price (5) samba (5) CGI (4) LISP (4) RoR (4) cache (4) car (4) display (4) holywar (4) nginx (4) pistol (4) spark (4) xml (4) Лебедев (4) IDE (3) IE8 (3) J2EE (3) NTFS (3) RDP (3) holiday (3) mount (3) Гоблин (3) кухня (3) урюк (3) AMQP (2) ERP (2) IE7 (2) NAS (2) Naudoc (2) PDF (2) address (2) air (2) british (2) coffee (2) fitness (2) font (2) ftp (2) fuckup (2) messaging (2) notify (2) sharepoint (2) ssl/tls (2) stardict (2) tests (2) tunnel (2) udev (2) APT (1) Baltic (1) CRUD (1) Canyonlands (1) Cyprus (1) DVDShrink (1) Jabber (1) K9Copy (1) Matlab (1) Portugal (1) VBA (1) WD My Book (1) autoit (1) bike (1) cannabis (1) chat (1) concurrent (1) dbf (1) ext4 (1) idioten (1) join (1) krusader (1) license (1) life (1) migration (1) mindmap (1) navitel (1) pneumatic weapon (1) quiz (1) regexp (1) robot (1) science (1) seaside (1) serialization (1) shore (1) spatial (1) tie (1) vim (1) Науру (1) крысы (1) налоги (1) пианино (1)