Browse Source

publish muk_session_store - 12.0

pull/9/head
MuK IT GmbH 6 years ago
parent
commit
5f8e3d6c6c
  1. 2
      muk_session_store/__manifest__.py
  2. 80
      muk_session_store/store/postgres.py
  3. 15
      muk_session_store/store/redis.py

2
muk_session_store/__manifest__.py

@ -20,7 +20,7 @@
{ {
"name": "MuK Session Store", "name": "MuK Session Store",
"summary": """Session Store Options""", "summary": """Session Store Options""",
"version": "12.0.1.0.5",
"version": "12.0.1.0.6",
"category": "Extra Tools", "category": "Extra Tools",
"license": "AGPL-3", "license": "AGPL-3",
"website": "http://www.mukit.at", "website": "http://www.mukit.at",

80
muk_session_store/store/postgres.py

@ -23,6 +23,7 @@ import psycopg2
import functools import functools
from contextlib import closing from contextlib import closing
from contextlib import contextmanager
from datetime import datetime, date from datetime import datetime, date
from werkzeug.contrib.sessions import SessionStore from werkzeug.contrib.sessions import SessionStore
@ -32,17 +33,15 @@ from odoo.tools import config
_logger = logging.getLogger(__name__) _logger = logging.getLogger(__name__)
def ensure_cursor(func):
def retry_database(func):
@functools.wraps(func) @functools.wraps(func)
def wrapper(self, *args, **kwargs): def wrapper(self, *args, **kwargs):
for attempts in range(1, 6): for attempts in range(1, 6):
try: try:
return func(self, *args, **kwargs) return func(self, *args, **kwargs)
except psycopg2.InterfaceError as error: except psycopg2.InterfaceError as error:
_logger.info("SessionStore connection failed! (%s/5)" % attempts)
if attempts < 5:
self._open_connection()
else:
_logger.warn("SessionStore connection failed! (%s/5)" % attempts)
if attempts >= 5:
raise error raise error
return wrapper return wrapper
@ -51,35 +50,27 @@ class PostgresSessionStore(SessionStore):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(PostgresSessionStore, self).__init__(*args, **kwargs) super(PostgresSessionStore, self).__init__(*args, **kwargs)
self.dbname = config.get('session_store_dbname', 'session_store') self.dbname = config.get('session_store_dbname', 'session_store')
self._open_connection()
self._setup_db()
self._setup_database(raise_exception=False)
def _setup_database(self, raise_exception=True):
try:
with db_connect(self.dbname, allow_uri=True).cursor() as cursor:
cursor.autocommit(True)
self._create_table(cursor)
except:
self._create_database()
self._setup_database()
def _create_database(self): def _create_database(self):
with closing(db_connect("postgres").cursor()) as cursor:
with db_connect("postgres").cursor() as cursor:
cursor.autocommit(True) cursor.autocommit(True)
cursor.execute(""" cursor.execute("""
CREATE DATABASE {dbname} CREATE DATABASE {dbname}
ENCODING 'unicode' ENCODING 'unicode'
TEMPLATE 'template0'; TEMPLATE 'template0';
""".format(dbname=self.dbname)) """.format(dbname=self.dbname))
self._setup_db()
def _open_connection(self, create_db=True):
try:
connection = db_connect(self.dbname, allow_uri=True)
self.cursor = connection.cursor()
self.cursor.autocommit(True)
except:
if not create_db:
raise
self._create_database()
return self._open_connection(create_db=False)
def __del__(self):
self.cursor.close()
@ensure_cursor
def _setup_db(self):
def _create_table(self, cursor):
self.cursor.execute(""" self.cursor.execute("""
CREATE TABLE IF NOT EXISTS sessions ( CREATE TABLE IF NOT EXISTS sessions (
sid varchar PRIMARY KEY, sid varchar PRIMARY KEY,
@ -88,31 +79,42 @@ class PostgresSessionStore(SessionStore):
); );
""") """)
@ensure_cursor
@contextmanager
def open_cursor(self):
connection = db_connect(self.dbname, allow_uri=True)
cursor = connection.cursor()
cursor.autocommit(True)
yield cursor
cursor.close()
@retry_database
def save(self, session): def save(self, session):
self.cursor.execute("""
with open_cursor() as cursor:
cursor.execute("""
INSERT INTO sessions (sid, write_date, payload) INSERT INTO sessions (sid, write_date, payload)
VALUES (%(sid)s, now() at time zone 'UTC', %(payload)s) VALUES (%(sid)s, now() at time zone 'UTC', %(payload)s)
ON CONFLICT (sid) ON CONFLICT (sid)
DO UPDATE SET payload = %(payload)s, write_date = now() at time zone 'UTC'; DO UPDATE SET payload = %(payload)s, write_date = now() at time zone 'UTC';
""", dict(sid=session.sid, payload=json.dumps(dict(session)))) """, dict(sid=session.sid, payload=json.dumps(dict(session))))
@ensure_cursor
@retry_database
def delete(self, session): def delete(self, session):
self.cursor.execute("DELETE FROM sessions WHERE sid=%s;", [session.sid])
with open_cursor() as cursor:
cursor.execute("DELETE FROM sessions WHERE sid=%s;", [session.sid])
@ensure_cursor
@retry_database
def get(self, sid): def get(self, sid):
if not self.is_valid_key(sid): if not self.is_valid_key(sid):
return self.new() return self.new()
self.cursor.execute("""
with open_cursor() as cursor:
cursor.execute("""
SELECT payload, write_date SELECT payload, write_date
FROM sessions WHERE sid=%s; FROM sessions WHERE sid=%s;
""", [sid]) """, [sid])
try: try:
payload, write_date = self.cursor.fetchone()
payload, write_date = cursor.fetchone()
if write_date.date() != datetime.today().date(): if write_date.date() != datetime.today().date():
self.cursor.execute("""
cursor.execute("""
UPDATE sessions UPDATE sessions
SET write_date = now() at time zone 'UTC' SET write_date = now() at time zone 'UTC'
WHERE sid=%s; WHERE sid=%s;
@ -121,14 +123,16 @@ class PostgresSessionStore(SessionStore):
except Exception: except Exception:
return self.session_class({}, sid, False) return self.session_class({}, sid, False)
@ensure_cursor
@retry_database
def list(self): def list(self):
self.cursor.execute("SELECT sid FROM sessions;")
return [record[0] for record in self.cursor.fetchall()]
with open_cursor() as cursor:
cursor.execute("SELECT sid FROM sessions;")
return [record[0] for record in cursor.fetchall()]
@ensure_cursor
@retry_database
def clean(self): def clean(self):
self.cursor.execute("""
with open_cursor() as cursor:
cursor.execute("""
DELETE FROM sessions DELETE FROM sessions
WHERE now() at time zone 'UTC' - write_date > '7 days'; WHERE now() at time zone 'UTC' - write_date > '7 days';
""") """)

15
muk_session_store/store/redis.py

@ -35,14 +35,14 @@ except ImportError:
SESSION_TIMEOUT = 60 * 60 * 24 * 7 SESSION_TIMEOUT = 60 * 60 * 24 * 7
def ensure_server(func):
def retry_redis(func):
@functools.wraps(func) @functools.wraps(func)
def wrapper(self, *args, **kwargs): def wrapper(self, *args, **kwargs):
for attempts in range(1, 6): for attempts in range(1, 6):
try: try:
return func(self, *args, **kwargs) return func(self, *args, **kwargs)
except redis.ConnectionError as error: except redis.ConnectionError as error:
_logger.info("SessionStore connection failed! (%s/5)" % attempts)
_logger.warn("SessionStore connection failed! (%s/5)" % attempts)
if attempts >= 5: if attempts >= 5:
raise error raise error
return wrapper return wrapper
@ -58,7 +58,6 @@ class RedisSessionStore(SessionStore):
db=int(config.get('session_store_dbindex', 1)), db=int(config.get('session_store_dbindex', 1)),
password=config.get('session_store_pass', None) password=config.get('session_store_pass', None)
) )
self._check_server()
def _encode_session_key(self, kex): def _encode_session_key(self, kex):
return key.encode('utf-8') if isinstance(key, str) else key return key.encode('utf-8') if isinstance(key, str) else key
@ -66,21 +65,17 @@ class RedisSessionStore(SessionStore):
def _get_session_key(self, sid): def _get_session_key(self, sid):
return self._encode_session_key(self.key_prefix + sid) return self._encode_session_key(self.key_prefix + sid)
@ensure_server
def _check_server(self):
self.server.ping()
@ensure_server
@retry_redis
def save(self, session): def save(self, session):
key = self._get_session_key(session.sid) key = self._get_session_key(session.sid)
payload = pickle.dumps(dict(session), pickle.HIGHEST_PROTOCOL) payload = pickle.dumps(dict(session), pickle.HIGHEST_PROTOCOL)
self.server.setex(name=key, value=payload, time=SESSION_TIMEOUT) self.server.setex(name=key, value=payload, time=SESSION_TIMEOUT)
@ensure_server
@retry_redis
def delete(self, session): def delete(self, session):
self.server.delete(self._get_session_key(session.sid)) self.server.delete(self._get_session_key(session.sid))
@ensure_server
@retry_redis
def get(self, sid): def get(self, sid):
if not self.is_valid_key(sid): if not self.is_valid_key(sid):
return self.new() return self.new()

Loading…
Cancel
Save