Skip to content

Commit b53d0a0

Browse files
committed
[MIG] session_db from 18 to 19
1 parent 5146d58 commit b53d0a0

File tree

5 files changed

+111
-26
lines changed

5 files changed

+111
-26
lines changed

session_db/README.rst

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
.. image:: https://odoo-community.org/readme-banner-image
2+
:target: https://odoo-community.org/get-involved?utm_source=readme
3+
:alt: Odoo Community Association
4+
15
====================
26
Store sessions in DB
37
====================
@@ -13,17 +17,17 @@ Store sessions in DB
1317
.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
1418
:target: https://odoo-community.org/page/development-status
1519
:alt: Beta
16-
.. |badge2| image:: https://img.shields.io/badge/licence-LGPL--3-blue.png
20+
.. |badge2| image:: https://img.shields.io/badge/license-LGPL--3-blue.png
1721
:target: http://www.gnu.org/licenses/lgpl-3.0-standalone.html
1822
:alt: License: LGPL-3
1923
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fserver--tools-lightgray.png?logo=github
20-
:target: https://github.com/OCA/server-tools/tree/18.0/session_db
24+
:target: https://github.com/OCA/server-tools/tree/19.0/session_db
2125
:alt: OCA/server-tools
2226
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
23-
:target: https://translation.odoo-community.org/projects/server-tools-18-0/server-tools-18-0-session_db
27+
:target: https://translation.odoo-community.org/projects/server-tools-19-0/server-tools-19-0-session_db
2428
:alt: Translate me on Weblate
2529
.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png
26-
:target: https://runboat.odoo-community.org/builds?repo=OCA/server-tools&target_branch=18.0
30+
:target: https://runboat.odoo-community.org/builds?repo=OCA/server-tools&target_branch=19.0
2731
:alt: Try me on Runboat
2832

2933
|badge1| |badge2| |badge3| |badge4| |badge5|
@@ -54,7 +58,7 @@ Bug Tracker
5458
Bugs are tracked on `GitHub Issues <https://github.com/OCA/server-tools/issues>`_.
5559
In case of trouble, please check there if your issue has already been reported.
5660
If you spotted it first, help us to smash it by providing a detailed and welcomed
57-
`feedback <https://github.com/OCA/server-tools/issues/new?body=module:%20session_db%0Aversion:%2018.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
61+
`feedback <https://github.com/OCA/server-tools/issues/new?body=module:%20session_db%0Aversion:%2019.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
5862

5963
Do not contact contributors directly about support or help with technical issues.
6064

@@ -88,6 +92,6 @@ Current `maintainer <https://odoo-community.org/page/maintainer-role>`__:
8892

8993
|maintainer-sbidoul|
9094

91-
This module is part of the `OCA/server-tools <https://github.com/OCA/server-tools/tree/18.0/session_db>`_ project on GitHub.
95+
This module is part of the `OCA/server-tools <https://github.com/OCA/server-tools/tree/19.0/session_db>`_ project on GitHub.
9296

9397
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

session_db/__manifest__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "Store sessions in DB",
3-
"version": "18.0.1.0.0",
3+
"version": "19.0.1.0.0",
44
"author": "Odoo SA,ACSONE SA/NV,Odoo Community Association (OCA)",
55
"license": "LGPL-3",
66
"website": "https://github.com/OCA/server-tools",

session_db/pg_session_store.py

Lines changed: 51 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
# @author Nicolas Seinlet
33
# Copyright (c) ACSONE SA 2022
44
# @author Stéphane Bidoul
5+
import functools
56
import json
67
import logging
78
import os
@@ -11,7 +12,6 @@
1112
import odoo
1213
from odoo import http
1314
from odoo.tools._vendor import sessions
14-
from odoo.tools.func import lazy_property
1515

1616
_logger = logging.getLogger(__name__)
1717

@@ -136,9 +136,12 @@ def get(self, sid):
136136

137137
return self.session_class(data, sid, False)
138138

139-
# This method is not part of the Session interface but is called nevertheless,
140-
# so let's get it from FilesystemSessionStore.
139+
# Odoo's FileSystemSessionStore has a few additional methods that are independent
140+
# of the actual storage backend. We reuse them here.
141141
rotate = http.FilesystemSessionStore.rotate
142+
generate_key = http.FilesystemSessionStore.generate_key
143+
is_valid_key = http.FilesystemSessionStore.is_valid_key
144+
delete_old_sessions = http.FilesystemSessionStore.delete_old_sessions
142145

143146
@with_lock
144147
@with_cursor
@@ -149,11 +152,54 @@ def vacuum(self, max_lifetime=http.SESSION_LIFETIME):
149152
(f"{max_lifetime} seconds",),
150153
)
151154

155+
@with_lock
156+
@with_cursor
157+
def get_missing_session_identifiers(self, identifiers: list[str]) -> set[str]:
158+
"""
159+
:param identifiers: session identifiers whose file existence must be checked
160+
identifiers are a part session sid (first 42 chars)
161+
:type identifiers: iterable
162+
:return: the identifiers which are not present on the filesystem
163+
:rtype: set
164+
165+
Note 1:
166+
Working with identifiers 42 characters long means that
167+
we don't have to work with the entire sid session,
168+
while maintaining sufficient entropy to avoid collisions.
169+
See details in ``generate_key``.
170+
171+
Note 2:
172+
Scans the session store for inactive (GC'd) sessions.
173+
Performance is acceptable for an infrequent background job.
174+
"""
175+
missing_identifiers = set()
176+
for identifier in identifiers:
177+
self._cr.execute(
178+
"SELECT sid FROM http_sessions WHERE sid LIKE %s||'%%' LIMIT 1",
179+
(identifier,),
180+
)
181+
if self._cr.rowcount == 0:
182+
missing_identifiers.add(identifier)
183+
return missing_identifiers
184+
185+
@with_lock
186+
@with_cursor
187+
def delete_from_identifiers(self, identifiers: list[str]) -> None:
188+
for identifier in identifiers:
189+
if not http._session_identifier_re.match(identifier):
190+
raise ValueError(
191+
"Identifier format incorrect, "
192+
"did you pass in a string instead of a list?"
193+
)
194+
self._cr.execute(
195+
"DELETE FROM http_sessions WHERE sid LIKE %s||'%%'", (identifier,)
196+
)
197+
152198

153199
_original_session_store = http.root.__class__.session_store
154200

155201

156-
@lazy_property
202+
@functools.cached_property
157203
def session_store(self):
158204
session_db_uri = os.environ.get("SESSION_DB_URI")
159205
if session_db_uri:
@@ -165,5 +211,6 @@ def session_store(self):
165211
# Monkey patch of standard methods
166212
_logger.debug("Monkey patching session store")
167213
http.root.__class__.session_store = session_store
214+
http.root.__class__.session_store.__set_name__(http.root.__class__, "session_store")
168215
# Reset the lazy property cache
169216
vars(http.root).pop("session_store", None)

session_db/static/description/index.html

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
<head>
44
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
55
<meta name="generator" content="Docutils: https://docutils.sourceforge.io/" />
6-
<title>Store sessions in DB</title>
6+
<title>README.rst</title>
77
<style type="text/css">
88

99
/*
@@ -360,16 +360,21 @@
360360
</style>
361361
</head>
362362
<body>
363-
<div class="document" id="store-sessions-in-db">
364-
<h1 class="title">Store sessions in DB</h1>
363+
<div class="document">
365364

365+
366+
<a class="reference external image-reference" href="https://odoo-community.org/get-involved?utm_source=readme">
367+
<img alt="Odoo Community Association" src="https://odoo-community.org/readme-banner-image" />
368+
</a>
369+
<div class="section" id="store-sessions-in-db">
370+
<h1>Store sessions in DB</h1>
366371
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
367372
!! This file is generated by oca-gen-addon-readme !!
368373
!! changes will be overwritten. !!
369374
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
370375
!! source digest: sha256:1f019db79d78ab20a204e51d1750ed8b2e7c22dd3d585569f97579c339bc34c7
371376
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
372-
<p><a class="reference external image-reference" href="https://odoo-community.org/page/development-status"><img alt="Beta" src="https://img.shields.io/badge/maturity-Beta-yellow.png" /></a> <a class="reference external image-reference" href="http://www.gnu.org/licenses/lgpl-3.0-standalone.html"><img alt="License: LGPL-3" src="https://img.shields.io/badge/licence-LGPL--3-blue.png" /></a> <a class="reference external image-reference" href="https://github.com/OCA/server-tools/tree/18.0/session_db"><img alt="OCA/server-tools" src="https://img.shields.io/badge/github-OCA%2Fserver--tools-lightgray.png?logo=github" /></a> <a class="reference external image-reference" href="https://translation.odoo-community.org/projects/server-tools-18-0/server-tools-18-0-session_db"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external image-reference" href="https://runboat.odoo-community.org/builds?repo=OCA/server-tools&amp;target_branch=18.0"><img alt="Try me on Runboat" src="https://img.shields.io/badge/runboat-Try%20me-875A7B.png" /></a></p>
377+
<p><a class="reference external image-reference" href="https://odoo-community.org/page/development-status"><img alt="Beta" src="https://img.shields.io/badge/maturity-Beta-yellow.png" /></a> <a class="reference external image-reference" href="http://www.gnu.org/licenses/lgpl-3.0-standalone.html"><img alt="License: LGPL-3" src="https://img.shields.io/badge/license-LGPL--3-blue.png" /></a> <a class="reference external image-reference" href="https://github.com/OCA/server-tools/tree/19.0/session_db"><img alt="OCA/server-tools" src="https://img.shields.io/badge/github-OCA%2Fserver--tools-lightgray.png?logo=github" /></a> <a class="reference external image-reference" href="https://translation.odoo-community.org/projects/server-tools-19-0/server-tools-19-0-session_db"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external image-reference" href="https://runboat.odoo-community.org/builds?repo=OCA/server-tools&amp;target_branch=19.0"><img alt="Try me on Runboat" src="https://img.shields.io/badge/runboat-Try%20me-875A7B.png" /></a></p>
373378
<p>Store sessions in a database instead of the filesystem. This simplifies
374379
the configuration of horizontally scalable deployments, by avoiding the
375380
need for a distributed filesystem to store the Odoo sessions.</p>
@@ -386,32 +391,32 @@ <h1 class="title">Store sessions in DB</h1>
386391
</ul>
387392
</div>
388393
<div class="section" id="usage">
389-
<h1><a class="toc-backref" href="#toc-entry-1">Usage</a></h1>
394+
<h2><a class="toc-backref" href="#toc-entry-1">Usage</a></h2>
390395
<p>Set this module in the server wide modules.</p>
391396
<p>Set a <tt class="docutils literal">SESSION_DB_URI</tt> environment variable as a full postgresql
392397
connection string, like <tt class="docutils literal"><span class="pre">postgres://user:passwd&#64;server/db</span></tt> or <tt class="docutils literal">db</tt>.</p>
393398
<p>It is recommended to use a dedicated database for this module, and
394399
possibly a dedicated postgres user for additional security.</p>
395400
</div>
396401
<div class="section" id="bug-tracker">
397-
<h1><a class="toc-backref" href="#toc-entry-2">Bug Tracker</a></h1>
402+
<h2><a class="toc-backref" href="#toc-entry-2">Bug Tracker</a></h2>
398403
<p>Bugs are tracked on <a class="reference external" href="https://github.com/OCA/server-tools/issues">GitHub Issues</a>.
399404
In case of trouble, please check there if your issue has already been reported.
400405
If you spotted it first, help us to smash it by providing a detailed and welcomed
401-
<a class="reference external" href="https://github.com/OCA/server-tools/issues/new?body=module:%20session_db%0Aversion:%2018.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**">feedback</a>.</p>
406+
<a class="reference external" href="https://github.com/OCA/server-tools/issues/new?body=module:%20session_db%0Aversion:%2019.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**">feedback</a>.</p>
402407
<p>Do not contact contributors directly about support or help with technical issues.</p>
403408
</div>
404409
<div class="section" id="credits">
405-
<h1><a class="toc-backref" href="#toc-entry-3">Credits</a></h1>
410+
<h2><a class="toc-backref" href="#toc-entry-3">Credits</a></h2>
406411
<div class="section" id="authors">
407-
<h2><a class="toc-backref" href="#toc-entry-4">Authors</a></h2>
412+
<h3><a class="toc-backref" href="#toc-entry-4">Authors</a></h3>
408413
<ul class="simple">
409414
<li>Odoo SA</li>
410415
<li>ACSONE SA/NV</li>
411416
</ul>
412417
</div>
413418
<div class="section" id="maintainers">
414-
<h2><a class="toc-backref" href="#toc-entry-5">Maintainers</a></h2>
419+
<h3><a class="toc-backref" href="#toc-entry-5">Maintainers</a></h3>
415420
<p>This module is maintained by the OCA.</p>
416421
<a class="reference external image-reference" href="https://odoo-community.org">
417422
<img alt="Odoo Community Association" src="https://odoo-community.org/logo.png" />
@@ -421,10 +426,11 @@ <h2><a class="toc-backref" href="#toc-entry-5">Maintainers</a></h2>
421426
promote its widespread use.</p>
422427
<p>Current <a class="reference external" href="https://odoo-community.org/page/maintainer-role">maintainer</a>:</p>
423428
<p><a class="reference external image-reference" href="https://github.com/sbidoul"><img alt="sbidoul" src="https://github.com/sbidoul.png?size=40px" /></a></p>
424-
<p>This module is part of the <a class="reference external" href="https://github.com/OCA/server-tools/tree/18.0/session_db">OCA/server-tools</a> project on GitHub.</p>
429+
<p>This module is part of the <a class="reference external" href="https://github.com/OCA/server-tools/tree/19.0/session_db">OCA/server-tools</a> project on GitHub.</p>
425430
<p>You are welcome to contribute. To learn how please visit <a class="reference external" href="https://odoo-community.org/page/Contribute">https://odoo-community.org/page/Contribute</a>.</p>
426431
</div>
427432
</div>
428433
</div>
434+
</div>
429435
</body>
430436
</html>

session_db/tests/test_pg_session_store.py

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
from odoo import http
77
from odoo.sql_db import connection_info_for
8-
from odoo.tests.common import TransactionCase
8+
from odoo.tests import TransactionCase
99
from odoo.tools import config
1010

1111
from odoo.addons.session_db.pg_session_store import PGSessionStore
@@ -33,7 +33,7 @@ def _make_postgres_uri(
3333
class TestPGSessionStore(TransactionCase):
3434
def setUp(self):
3535
super().setUp()
36-
_, connection_info = connection_info_for(config["db_name"])
36+
_, connection_info = connection_info_for(config["db_name"][0])
3737
self.session_store = PGSessionStore(
3838
_make_postgres_uri(**connection_info), session_class=http.Session
3939
)
@@ -79,8 +79,8 @@ def test_retry_connect_fail(self):
7979
# get fails, and a RuntimeError is raised when trying to reconnect
8080
try:
8181
self.session_store.get("abc")
82-
except RuntimeError: # pylint: disable=except-pass
83-
pass
82+
except RuntimeError as e: # pylint: disable=except-pass
83+
assert str(e) == "connection failed"
8484
else:
8585
# We don't use self.assertRaises because Odoo is overriding
8686
# in a way that interferes with the Cursor.execute mock
@@ -100,3 +100,31 @@ def test_make_postgres_uri(self):
100100
assert "postgres://test:PASSWORD@localhost:5432/test" == _make_postgres_uri(
101101
**connection_info
102102
)
103+
104+
def test_get_missing_session_identifiers(self):
105+
session1 = self.session_store.new()
106+
session2 = self.session_store.new()
107+
self.session_store.save(session1)
108+
self.session_store.save(session2)
109+
missing = self.session_store.get_missing_session_identifiers(
110+
[session1.sid[:42], session2.sid[:42], "nonexistentsessionid"]
111+
)
112+
self.assertEqual(missing, {"nonexistentsessionid"})
113+
self.session_store.delete(session1)
114+
missing = self.session_store.get_missing_session_identifiers(
115+
[session1.sid[:42], session2.sid[:42], "nonexistentsessionid"]
116+
)
117+
self.assertEqual(missing, {session1.sid[:42], "nonexistentsessionid"})
118+
119+
def test_delete_from_identifiers(self):
120+
session1 = self.session_store.new()
121+
session2 = self.session_store.new()
122+
self.session_store.save(session1)
123+
self.session_store.save(session2)
124+
self.session_store.delete_from_identifiers([session1.sid[:42], "f" * 42])
125+
self.assertNotEqual(self.session_store.get(session1.sid).sid, session1.sid)
126+
self.assertEqual(self.session_store.get(session2.sid).sid, session2.sid)
127+
128+
def test_delete_from_identifiers_invalid_format(self):
129+
with self.assertRaises(ValueError):
130+
self.session_store.delete_from_identifiers("xxx")

0 commit comments

Comments
 (0)