Skip to content

Commit b7eeffa

Browse files
committed
db: configure read replica request routing
1 parent 4c27fc4 commit b7eeffa

File tree

2 files changed

+131
-0
lines changed

2 files changed

+131
-0
lines changed

invenio.cfg

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ from zenodo_rdm.custom_fields import (
7373
NAMESPACES,
7474
)
7575
from zenodo_rdm.custom_schemes import is_edmo
76+
from zenodo_rdm.db import routed_bind
7677
from zenodo_rdm.files import storage_factory
7778
from zenodo_rdm.github.schemas import CitationMetadataSchema
7879
from zenodo_rdm.legacy.resources import record_serializers
@@ -149,6 +150,114 @@ if _parse_env_bool("INVENIO_PGBOUNCER_ENABLED", False):
149150
else:
150151
SQLALCHEMY_DATABASE_URI = "postgresql+psycopg2://zenodo:zenodo@localhost/zenodo"
151152

153+
# fmt: off
154+
ZENODO_UI_READ_ONLY_ENDPOINTS = [
155+
"invenio_app_rdm.frontpage_view_function", # /
156+
"invenio_app_rdm_records.record_from_pid", # /<any(doi,oai):pid_scheme>/<path:pid_value>
157+
"invenio_redirector.redirect_about", # /about
158+
"invenio_formatter_badges.badge", # png):ext>
159+
"invenio_github_badge.index", # /badge/<int:repo_github_id>.svg
160+
"invenio_github_badge.index_old", # /badge/<int:user_id>/<path:repo_name>.svg
161+
"invenio_github_badge.latest_doi", # /badge/latestdoi/<int:github_id>
162+
"invenio_github_badge.latest_doi_old", # /badge/latestdoi/<int:user_id>/<path:repo_name>
163+
"invenio_redirector.redirect_communities_search_legacy", # /collection/<type>
164+
"invenio_redirector.redirect_collections_about", # /collection/user-<id>
165+
"invenio_communities.communities_frontpage", # /communities
166+
"invenio_communities.communities_search", # /communities-search
167+
"invenio_redirector.redirect_communities_curate", # /communities/<community_id>/curate
168+
"invenio_redirector.redirect_communities_edt", # /communities/<community_id>/edit
169+
"invenio_redirector.redirect_communities_search", # /communities/<community_id>/search
170+
"invenio_app_rdm_communities.communities_home", # /communities/<pid_value>/
171+
"invenio_communities.communities_about", # /communities/<pid_value>/about
172+
"invenio_app_rdm_communities.communities_browse", # /communities/<pid_value>/browse
173+
"invenio_communities.communities_subcommunities", # /communities/<pid_value>/browse/subcommunities
174+
"invenio_app_rdm_communities.community_collection", # /communities/<pid_value>/collections/<tree_slug>/<collection_slug>
175+
"invenio_communities.community_theme_css_config", # /communities/<pid_value>/community-theme-<revision>.css
176+
"invenio_communities.communities_curation_policy", # /communities/<pid_value>/curation-policy
177+
"invenio_communities.members", # /communities/<pid_value>/members
178+
"invenio_app_rdm_communities.community_static_page", # /communities/<pid_value>/pages/<path:page_slug>
179+
"invenio_app_rdm_communities.communities_detail", # /communities/<pid_value>/records
180+
"invenio_redirector.redirect_communities_about_legacy", # /communities/about/<id>
181+
"invenio_communities.deprecated_communities_search", # /communities/search
182+
"invenio_redirector.redirect_contact", # /contact
183+
"invenio_redirector.redirect_dev", # /dev
184+
"invenio_redirector.redirect_donate", # /donate
185+
"invenio_redirector.redirect_faq", # /faq
186+
"invenio_redirector.redirect_features", # /features
187+
"invenio_app_rdm.help_search", # /help/search
188+
"invenio_app_rdm.help_statistics", # /help/statistics
189+
"invenio_app_rdm.help_versioning", # /help/versioning
190+
"invenio_redirector.redirect_policies", # /policies
191+
"invenio_redirector.redirect_privacy-policy", # /privacy-policy
192+
"invenio_redirector.redirect_record_detail", # /record/<pid_value>
193+
"invenio_redirector.redirect_record_export", # /record/<pid_value>/export/<export_format>
194+
"invenio_redirector.redirect_record_file_download", # /record/<pid_value>/files/<path:filename>
195+
"invenio_redirector.redirect_formats_to_media_files", # /record/<pid_value>/formats
196+
"invenio_redirector.redirect_record_file_preview", # /record/<pid_value>/preview/<path:filename>
197+
"invenio_redirector.redirect_record_thumbnail", # /record/<pid_value>/thumb<size>
198+
"invenio_app_rdm_records.record_detail", # /records/<pid_value>
199+
"invenio_app_rdm_records.record_export", # /records/<pid_value>/export/<export_format>
200+
"invenio_redirector.redirect_legacy_record_export_view_dcat", # /records/<pid_value>/export/dcat
201+
"invenio_redirector.redirect_legacy_record_export_view_dcite4", # /records/<pid_value>/export/dcite4
202+
"invenio_redirector.redirect_legacy_record_export_view_hx", # /records/<pid_value>/export/hx
203+
"invenio_redirector.redirect_legacy_record_export_view_xd", # /records/<pid_value>/export/xd
204+
"invenio_redirector.redirect_legacy_record_export_view_xm", # /records/<pid_value>/export/xm
205+
"invenio_app_rdm_records.record_file_download", # /records/<pid_value>/files/<path:filename>
206+
"invenio_app_rdm_records.record_latest", # /records/<pid_value>/latest
207+
"invenio_app_rdm_records.record_media_file_download", # /records/<pid_value>/media-files/<path:filename>
208+
"invenio_app_rdm_records.record_file_preview", # /records/<pid_value>/preview/<path:filename>
209+
"invenio_app_rdm_records.record_thumbnail", # /records/<pid_value>/thumb<int:size>
210+
"invenio_search_ui.search", # /search
211+
"invenio_redirector.redirect_terms", # /terms
212+
]
213+
214+
ZENODO_API_READ_ONLY_ENDPOINTS = [
215+
"collections.search_records", # /collections/<id>/records
216+
"communities.search", # /communities
217+
"communities.read", # /communities/<pid_value>
218+
"communities.featured_list", # /communities/<pid_value>/featured
219+
"communities.read_logo", # /communities/<pid_value>/logo
220+
"community_members.search", # /communities/<pid_value>/members
221+
"community_members.search_public", # /communities/<pid_value>/members/public
222+
"community-records.search", # /communities/<pid_value>/records
223+
"communities.search_subcommunities", # /communities/<pid_value>/subcommunities
224+
"communities.featured_communities_search", # /communities/featured
225+
"exporter.list_object_versions", # /exporter
226+
"exporter.get_object_version_content", # /exporter/<path:key>
227+
"exporter.get_object_version_content", # /exporter/<path:key>/<uuid:version_id>
228+
"iiif.base", # /iiif/<path:uuid>
229+
"iiif.image_api", # /iiif/<path:uuid>/<region>/<size>/<rotation>/<quality>.<image_format>
230+
"iiif.canvas", # /iiif/<path:uuid>/canvas/<path:file_name>
231+
"iiif.info", # /iiif/<path:uuid>/info.json
232+
"iiif.manifest", # /iiif/<path:uuid>/manifest
233+
"iiif.sequence", # /iiif/<path:uuid>/sequence/default
234+
"records.search", # /records
235+
"zenodo_api_redirector.redirect_records_search_slash", # /records/
236+
"records.read", # /records/<pid_value>
237+
"record_files.search", # /records/<pid_value>/files
238+
"record_files.read_archive", # /records/<pid_value>/files-archive
239+
"record_files.read", # /records/<pid_value>/files/<path:key>
240+
"record_files.read_content", # /records/<pid_value>/files/<path:key>/content
241+
"record_media_files.search", # /records/<pid_value>/media-files
242+
"record_media_files.read_archive", # /records/<pid_value>/media-files-archive
243+
"record_media_files.read", # /records/<pid_value>/media-files/<key>
244+
"record_media_files.read_content", # /records/<pid_value>/media-files/<key>/content
245+
"records.search_versions", # /records/<pid_value>/versions
246+
"records.read_latest", # /records/<pid_value>/versions/latest
247+
]
248+
# fmt: on
249+
250+
ZENODO_READ_REPLICA_ENDPOINTS = (
251+
ZENODO_UI_READ_ONLY_ENDPOINTS + ZENODO_API_READ_ONLY_ENDPOINTS
252+
)
253+
if IS_LOCAL_DEV:
254+
SQLALCHEMY_BINDS = {
255+
"read_replica": "postgresql+psycopg2://zenodo_ro:zenodo_ro@localhost/zenodo"
256+
}
257+
258+
DB_SESSION_BIND_FUNC = routed_bind
259+
260+
152261
# Invenio-App
153262
# ===========
154263
# See https://invenio-app.readthedocs.io/en/latest/configuration.html

site/zenodo_rdm/db.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# -*- coding: utf-8 -*-
2+
#
3+
# Copyright (C) 2025 CERN.
4+
#
5+
# ZenodoRDM is free software; you can redistribute it and/or modify it
6+
# under the terms of the MIT License; see LICENSE file for more details.
7+
"""Database helpers."""
8+
9+
from flask import current_app, request
10+
from flask_login import current_user
11+
12+
13+
def routed_bind(session, *args, **kwargs):
14+
"""Route session to the appropriate database depending on the request context.
15+
16+
Routes unauthenticated/anonymous GET and HEAD requests of configured endpoints to
17+
the configured read replica SQLAlchemy bind.
18+
"""
19+
if request and request.method in ["GET", "HEAD"]:
20+
read_endpoints = current_app.config.get("ZENODO_READ_REPLICA_ENDPOINTS", [])
21+
if current_user.is_anonymous and request.endpoint in read_endpoints:
22+
return session._db.engines["read_replica"]

0 commit comments

Comments
 (0)