Skip to content

Commit 79cddd6

Browse files
committed
Merge PR #2871 into 17.0
Signed-off-by thomaspaulb
2 parents 8d7123e + 1dd5e61 commit 79cddd6

18 files changed

Lines changed: 1001 additions & 0 deletions

bus_alt_connection/README.rst

Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,190 @@
1+
==================
2+
Bus Alt Connection
3+
==================
4+
5+
..
6+
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
7+
!! This file is generated by oca-gen-addon-readme !!
8+
!! changes will be overwritten. !!
9+
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
10+
!! source digest: sha256:ab7e1b9d5721f8cb27f93c58ed77e5034bc0099105ac6d5097f1bdc74a4e6973
11+
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
12+
13+
.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
14+
:target: https://odoo-community.org/page/development-status
15+
:alt: Beta
16+
.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png
17+
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
18+
:alt: License: AGPL-3
19+
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fserver--tools-lightgray.png?logo=github
20+
:target: https://github.com/OCA/server-tools/tree/16.0/bus_alt_connection
21+
:alt: OCA/server-tools
22+
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
23+
:target: https://translation.odoo-community.org/projects/server-tools-16-0/server-tools-16-0-bus_alt_connection
24+
:alt: Translate me on Weblate
25+
.. |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=16.0
27+
:alt: Try me on Runboat
28+
29+
|badge1| |badge2| |badge3| |badge4| |badge5|
30+
31+
This module makes it possible to use PgBouncer_ as a connection pooler
32+
for odoo.
33+
34+
.. _PgBouncer: https://pgbouncer.github.io/
35+
36+
Why isn't odoo's connection pooling good enough?
37+
================================================
38+
39+
Odoo's builtin connection pooling works at process level: each Odoo process
40+
has its own ConnectionPool_, limited to ``db_maxconn``.
41+
42+
It does the job of re-using open connections available in the pool.
43+
But it never closes these connections, `unless reaching db_maxconn`_.
44+
45+
.. _ConnectionPool: https://github.com/odoo/odoo/blob/12.0/odoo/sql_db.py#L525
46+
.. _`unless reaching db_maxconn`: https://github.com/odoo/odoo/blob/12.0/odoo/sql_db.py#L593
47+
48+
In practice, we observe that each odoo worker will end up
49+
with up to 3 open connection in its pool.
50+
With 10 http workers, that's up to 30 connection continuously open just
51+
for one single instance.
52+
53+
Here comes PgBouncer
54+
====================
55+
56+
PgBouncer will help to limit this number of open connections,
57+
by sharing a pool of connections at the instance level, between
58+
all workers. Odoo workers will still have up to 3 open connections,
59+
but these will be connections to PgBouncer, that on its side will
60+
close unnecessary connections to pg.
61+
62+
This has proven to help performances on Odoo deployments with
63+
multiple instances.
64+
65+
It allows you to define how resources should be shared,
66+
according to your priorities, e.g. :
67+
68+
* key odoo instance on host A can open up to 30 connections
69+
* while odoo instance on host B, dedicated to reports,
70+
can open up to 10 connections only
71+
72+
And most importantly, it helps you to ensure that
73+
``max_connections`` will never be reached on pg server side.
74+
75+
76+
Why is this module needed?
77+
==========================
78+
79+
When configuring PgBouncer, you can choose between 2 transaction pooling modes:
80+
81+
* `pool_mode = session`
82+
* `pool_mode = transaction`
83+
84+
If we choose `pool_mode = session`, then one server connection will be tied
85+
to a given odoo process until its death, which is exactly what we're trying
86+
to change. Thus, to release the server connection once the transaction is
87+
complete, we use `pool_mode = transaction`.
88+
89+
This works fine, except for Odoo's longpolling features that relies
90+
on the `LISTEN/NOTIFY`_ mechanism from pg, which is `not compatible`_ with that
91+
mode.
92+
93+
.. _`LISTEN/NOTIFY`: https://www.postgresql.org/docs/9.6/static/sql-notify.html
94+
.. _`not compatible`: https://wiki.postgresql.org/wiki/PgBouncer
95+
96+
97+
To be more precise, `NOTIFY` statements are properly transfered by PgBouncer
98+
in that mode; only the `LISTEN` statement isn't (because it needs to keep the
99+
server connection open).
100+
101+
So for the unique "listening" connection per instance that requires this
102+
statement (here_), we need odoo to connect directly to the pg server, bypassing
103+
PgBouncer.
104+
105+
That's what this module implements, by overriding the relevant method
106+
of the Dispatcher_.
107+
108+
.. _here: https://github.com/odoo/odoo/blob/12.0/addons/bus/models/bus.py#L166
109+
.. _Dispatcher: https://github.com/odoo/odoo/blob/12.0/addons/bus/models/bus.py#L105
110+
111+
**Table of contents**
112+
113+
.. contents::
114+
:local:
115+
116+
Installation
117+
============
118+
119+
You don't need to install this module in the database(s) to enable it.
120+
121+
But you need to load it server-wide:
122+
123+
* By starting Odoo with ``--load=web,bus_alt_connection``
124+
125+
* Or by updating its configuration file:
126+
127+
.. code-block:: ini
128+
129+
[options]
130+
(...)
131+
server_wide_modules = web,bus_alt_connection
132+
133+
Configuration
134+
=============
135+
136+
You need to define how to connect directly to the database:
137+
138+
* Either by defining environment variables:
139+
140+
- ``IMDISPATCHER_DB_HOST=db-01``
141+
- ``IMDISPATCHER_DB_PORT=5432``
142+
143+
* Or in Odoo's configuration file:
144+
145+
.. code-block:: ini
146+
147+
[options]
148+
(...)
149+
imdispatcher_db_host = db-01
150+
imdispatcher_db_port = 5432
151+
152+
Bug Tracker
153+
===========
154+
155+
Bugs are tracked on `GitHub Issues <https://github.com/OCA/server-tools/issues>`_.
156+
In case of trouble, please check there if your issue has already been reported.
157+
If you spotted it first, help us to smash it by providing a detailed and welcomed
158+
`feedback <https://github.com/OCA/server-tools/issues/new?body=module:%20bus_alt_connection%0Aversion:%2016.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
159+
160+
Do not contact contributors directly about support or help with technical issues.
161+
162+
Credits
163+
=======
164+
165+
Authors
166+
~~~~~~~
167+
168+
* Trobz
169+
170+
Contributors
171+
~~~~~~~~~~~~
172+
173+
* Nils Hamerlinck <nils@trobz.com>
174+
175+
Maintainers
176+
~~~~~~~~~~~
177+
178+
This module is maintained by the OCA.
179+
180+
.. image:: https://odoo-community.org/logo.png
181+
:alt: Odoo Community Association
182+
:target: https://odoo-community.org
183+
184+
OCA, or the Odoo Community Association, is a nonprofit organization whose
185+
mission is to support the collaborative development of Odoo features and
186+
promote its widespread use.
187+
188+
This module is part of the `OCA/server-tools <https://github.com/OCA/server-tools/tree/16.0/bus_alt_connection>`_ project on GitHub.
189+
190+
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

bus_alt_connection/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Copyright 2019 Trobz <https://trobz.com>
2+
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
3+
from . import models

bus_alt_connection/__manifest__.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# Copyright 2019 Trobz <https://trobz.com>
2+
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
3+
4+
{
5+
"name": "Bus Alt Connection",
6+
"summary": "Needed when using PgBouncer as a connection pooler",
7+
"version": "17.0.1.0.0",
8+
"author": "Trobz,Odoo Community Association (OCA)",
9+
"website": "https://github.com/OCA/server-tools",
10+
"category": "Extra Tools",
11+
"license": "AGPL-3",
12+
"depends": ["bus"],
13+
"installable": True,
14+
"auto_install": False,
15+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Translation of Odoo Server.
2+
# This file contains the translation of the following modules:
3+
#
4+
msgid ""
5+
msgstr ""
6+
"Project-Id-Version: Odoo Server 14.0\n"
7+
"Report-Msgid-Bugs-To: \n"
8+
"Last-Translator: \n"
9+
"Language-Team: \n"
10+
"MIME-Version: 1.0\n"
11+
"Content-Type: text/plain; charset=UTF-8\n"
12+
"Content-Transfer-Encoding: \n"
13+
"Plural-Forms: \n"
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Copyright 2019 Trobz <https://trobz.com>
2+
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
3+
from . import bus

bus_alt_connection/models/bus.py

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
# Copyright 2019 Trobz <https://trobz.com>
2+
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
3+
4+
import json
5+
import logging
6+
import os
7+
import selectors
8+
9+
import psycopg2
10+
11+
import odoo
12+
from odoo.tools import config
13+
14+
import odoo.addons.bus.models.bus
15+
from odoo.addons.bus.models.bus import TIMEOUT, hashable, stop_event
16+
17+
_logger = logging.getLogger(__name__)
18+
19+
20+
def _connection_info_for(db_name):
21+
db_or_uri, connection_info = odoo.sql_db.connection_info_for(db_name)
22+
23+
for p in ("host", "port"):
24+
cfg = os.environ.get("ODOO_IMDISPATCHER_DB_%s" % p.upper()) or config.get(
25+
"imdispatcher_db_" + p
26+
)
27+
if cfg:
28+
connection_info[p] = cfg
29+
return connection_info
30+
31+
32+
class ImDispatch(odoo.addons.bus.models.bus.ImDispatch):
33+
def loop(self):
34+
"""Dispatch postgres notifications to the relevant
35+
polling threads/greenlets"""
36+
connection_info = _connection_info_for("postgres")
37+
_logger.info(
38+
"Bus.loop listen imbus on db postgres " "(via %(host)s:%(port)s)",
39+
connection_info,
40+
)
41+
conn = psycopg2.connect(**connection_info)
42+
with conn.cursor() as cr, selectors.DefaultSelector() as sel:
43+
cr.execute("listen imbus")
44+
conn.commit()
45+
sel.register(conn, selectors.EVENT_READ)
46+
while not stop_event.is_set():
47+
if sel.select(TIMEOUT):
48+
conn.poll()
49+
channels = []
50+
while conn.notifies:
51+
channels.extend(json.loads(conn.notifies.pop().payload))
52+
# relay notifications to websockets that have
53+
# subscribed to the corresponding channels.
54+
websockets = set()
55+
for channel in channels:
56+
websockets.update(
57+
self._channels_to_ws.get(hashable(channel), [])
58+
)
59+
for websocket in websockets:
60+
websocket.trigger_notification_dispatching()
61+
62+
63+
odoo.addons.bus.models.bus.ImDispatch = ImDispatch
64+
dispatch = ImDispatch()
65+
odoo.addons.bus.models.bus.dispatch = dispatch
66+
odoo.addons.bus.models.ir_websocket.dispatch = dispatch
67+
odoo.addons.bus.websocket.dispatch = dispatch

bus_alt_connection/pyproject.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[build-system]
2+
requires = ["whool"]
3+
build-backend = "whool.buildapi"
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
You need to define how to connect directly to the database:
2+
3+
- Either by defining environment variables:
4+
5+
> - `IMDISPATCHER_DB_HOST=db-01`
6+
> - `IMDISPATCHER_DB_PORT=5432`
7+
8+
- Or in Odoo's configuration file:
9+
10+
``` ini
11+
[options]
12+
(...)
13+
imdispatcher_db_host = db-01
14+
imdispatcher_db_port = 5432
15+
```
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
You need to define how to connect directly to the database:
2+
3+
* Either by defining environment variables:
4+
5+
- ``IMDISPATCHER_DB_HOST=db-01``
6+
- ``IMDISPATCHER_DB_PORT=5432``
7+
8+
* Or in Odoo's configuration file:
9+
10+
.. code-block:: ini
11+
12+
[options]
13+
(...)
14+
imdispatcher_db_host = db-01
15+
imdispatcher_db_port = 5432
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
- Nils Hamerlinck \<<nils@trobz.com>\>

0 commit comments

Comments
 (0)