Странная ситуация. Пишу механизм сессий для Tornado в PostgreSQL. Логика вроде проста: в prepare() каждого запроса - смотрю, есть ли секурная кука sesion_id, если нет ее - создаю новую сессию, если есть - загружаю данные сессии из БД. Но вот не тут-то было.
class BaseHandler(tornado.web.RequestHandler):
''' от этого класса наследуются хендлеры '''
def get_session(self):
sessionId = self.get_secure_cookie("session_id")
logger.debug("BaseHandler.get_session: %s" % sessionId)
session = None
if (sessionId == None) :
session = SessionManager._create_session()
else :
session = SessionManager._load_session(sessionId)
return session
def prepare(self):
self.session = self.get_session()
def on_finish(self):
sessionId = self.set_secure_cookie("session_id", self.session.session_id)
SessionManager._save_session(self.session)
class SessionManager(Manager):
@staticmethod
def _create_session(sessionId=''):
sessionId = SessionManager._create_session_id() if (not sessionId or sessionId == '') else sessionId
logger.debug("SessionManager._create_session: %s" % sessionId)
while (SessionManager._check_session_id_exists(sessionId)) :
sessionId = SessionManager._create_session_id()
s = Connection.getSession()
session = Session(session_id = sessionId)
session.restore_data()
s.add(session)
s.commit()
#s.close()
return session
@staticmethod
def _load_session(sessionId:str):
logger.debug("SessionManager._load_session: %s" % sessionId)
s = Connection.getSession()
session = s.query(Session).filter(Session.session_id == sessionId).first()
#s.close()
if (session) :
logger.debug("SessionManager._load_session: loaded")
else :
logger.debug("SessionManager._load_session: not found, creating a new one")
session = SessionManager._create_session(sessionId)
return session
@staticmethod
def _check_session_id_exists(sessionId:str):
logger.debug("SessionManager._check_session_id: %s" % sessionId)
s = Connection.getSession()
if (s.query(Session).filter(Session.session_id == sessionId).first()) :
s.close()
return True
else :
s.close()
return False
@staticmethod
def _save_session(session):
session.pack_data()
logger.debug("SessionManager._save_session: %s" % session.session_data)
s = Connection.getSession()
s.add(session)
s.commit()
s.close()
Проблема в закрытии connection-ов в БД. Если в _load_session и _create_session я их закрываю, то в _save_session получаю ошибку:
sqlalchemy.orm.exc.DetachedInstanceError: Instance <Session at 0x1cb43c82e80> is not bound to a Session; attribute refresh operation cannot proceed
А если я в _load_session и _create_session оставляю connection в БД открытым, то ошибка:
sqlalchemy.exc.InvalidRequestError: Object '<Session at 0x27ba5fa9e80>' is already attached to session '2' (this is '3')
Так как же быть? Как правильно подключать сессии в Tornado?