Skip to content

Commit ee0aaf6

Browse files
committed
init: build broker url from its parts if available
1 parent 869c18d commit ee0aaf6

File tree

3 files changed

+99
-0
lines changed

3 files changed

+99
-0
lines changed

CHANGES.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@
99
Changes
1010
=======
1111

12+
Version <next>
13+
14+
- init: create broker url from its parts if available
15+
1216
Version 2.0.0 (released 2024-12-02)
1317

1418
- setup: bump invenio dependencies

invenio_celery/ext.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,41 @@ def load_entry_points(self):
6868
packages, related_name=related_name, force=True
6969
)
7070

71+
def build_broker_url(self, app):
72+
"""Return the broker connection string if configured or build it from its parts.
73+
74+
If set, then ``BROKER_URL`` will be returned.
75+
Otherwise, the URI will be pieced together by the configuration items
76+
``AMQP_BROKER_{USER,PASSWORD,HOST,PORT,NAME,PROTOCOL}``.
77+
If that cannot be done (e.g. because required values are missing), then
78+
``None`` will be returned.
79+
80+
Note: see: https://docs.celeryq.dev/en/stable/userguide/configuration.html#new-lowercase-settings
81+
"""
82+
if uri := app.config.get("BROKER_URL"):
83+
return uri
84+
85+
params = {}
86+
for config_name in ["USER", "PASSWORD", "HOST", "PORT", "VHOST", "PROTOCOL"]:
87+
params[config_name] = app.config.get(f"AMQP_BROKER_{config_name}", None)
88+
89+
required_params = ["USER", "PASSWORD", "HOST", "PORT", "PROTOCOL"]
90+
if all({params.get(p, None) for p in required_params}):
91+
vhost = (params.get("VHOST") or "").lstrip("/")
92+
uri = f"{params['PROTOCOL']}://{params['USER']}:{params['PASSWORD']}@{params['HOST']}:{params['PORT']}/{vhost}"
93+
return uri
94+
elif any(params.values()):
95+
app.logger.warn(
96+
'Ignoring "AMQP_BROKER_*" config values as they are only partially set.'
97+
)
98+
99+
return None
100+
71101
def init_config(self, app):
72102
"""Initialize configuration."""
103+
if broker_url := self.build_broker_url(app):
104+
app.config["BROKER_URL"] = broker_url
105+
73106
for k in dir(config):
74107
if k.startswith("CELERY_") or k.startswith("BROKER_"):
75108
app.config.setdefault(k, getattr(config, k))

tests/test_invenio_celery.py

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
from unittest.mock import MagicMock, patch
1212

1313
import pytest
14+
from flask import Flask
1415
from pkg_resources import EntryPoint
1516

1617
from invenio_celery import InvenioCelery
@@ -147,3 +148,64 @@ def _mock():
147148

148149
ext.get_active_tasks = _mock
149150
ext.suspend_queues(["feed"], sleep_time=0.1)
151+
152+
153+
@pytest.mark.parametrize(
154+
"configs, expected_url",
155+
[
156+
(
157+
{
158+
"AMQP_BROKER_USER": "testuser",
159+
"AMQP_BROKER_PASSWORD": "testpassword",
160+
"AMQP_BROKER_HOST": "testhost",
161+
"AMQP_BROKER_PORT": "5672",
162+
"AMQP_BROKER_PROTOCOL": "amqp",
163+
"AMQP_BROKER_VHOST": "/testvhost",
164+
},
165+
"amqp://testuser:testpassword@testhost:5672/testvhost",
166+
),
167+
(
168+
{
169+
"AMQP_BROKER_USER": "testuser",
170+
"AMQP_BROKER_PASSWORD": "testpassword",
171+
"AMQP_BROKER_HOST": "testhost",
172+
"AMQP_BROKER_PORT": "5672",
173+
"AMQP_BROKER_PROTOCOL": "amqp",
174+
"AMQP_BROKER_VHOST": "testvhost",
175+
},
176+
"amqp://testuser:testpassword@testhost:5672/testvhost",
177+
),
178+
(
179+
{
180+
"AMQP_BROKER_USER": "testuser",
181+
"AMQP_BROKER_PASSWORD": "testpassword",
182+
"AMQP_BROKER_HOST": "testhost",
183+
"AMQP_BROKER_PORT": "5672",
184+
"AMQP_BROKER_PROTOCOL": "amqp",
185+
"AMQP_BROKER_VHOST": "",
186+
},
187+
"amqp://testuser:testpassword@testhost:5672/",
188+
),
189+
(
190+
{
191+
"AMQP_BROKER_USER": "testuser",
192+
"AMQP_BROKER_PASSWORD": "testpassword",
193+
"AMQP_BROKER_HOST": "testhost",
194+
"AMQP_BROKER_PORT": "5672",
195+
"AMQP_BROKER_PROTOCOL": "amqp",
196+
},
197+
"amqp://testuser:testpassword@testhost:5672/",
198+
),
199+
(
200+
{},
201+
"redis://localhost:6379/0",
202+
),
203+
],
204+
)
205+
def test_build_broker_url_with_vhost(configs, expected_url):
206+
"""Test building broker URL with vhost."""
207+
app = Flask("test_app")
208+
assert "BROKER_URL" not in app.config
209+
app.config.update(configs)
210+
InvenioCelery(app)
211+
assert app.config["BROKER_URL"] == expected_url

0 commit comments

Comments
 (0)