From 9c456dc499377703165179f973d6762a95277f1c Mon Sep 17 00:00:00 2001 From: Kartik Ohri Date: Thu, 8 Feb 2024 19:43:11 +0530 Subject: [PATCH] Fix app init in case timescale listenstore is down SQLALCHEMY_TIMESCALE_URI can be empty if listenstore_up is set to false in consul config. In such cases, we want to bring up the flask app with whatever parts possible so that submit listens endpoint keeps working. Currently, this breaks during flask admin init and leads to app creation errors. Add timescale uri to sqlalchemy binds only if listenstore is available and only register playlist admin views under the same condition. --- consul_config.py.ctmpl | 11 +++---- listenbrainz/webserver/__init__.py | 48 +++++++++++++++++------------- 2 files changed, 34 insertions(+), 25 deletions(-) diff --git a/consul_config.py.ctmpl b/consul_config.py.ctmpl index 4a44052f55..a5d6db14a4 100644 --- a/consul_config.py.ctmpl +++ b/consul_config.py.ctmpl @@ -80,16 +80,22 @@ MB_DATABASE_URI = "" SQLALCHEMY_TIMESCALE_URI = """postgresql://listenbrainz_ts:{{template "KEY" "timescale_lb_password"}}@{{.Address}}:{{.Port}}/listenbrainz_ts""" TIMESCALE_ADMIN_URI = """postgresql://postgres:{{template "KEY" "timescale_admin_password"}}@{{.Address}}:{{.Port}}/postgres""" TIMESCALE_ADMIN_LB_URI = """postgresql://postgres:{{template "KEY" "timescale_admin_password"}}@{{.Address}}:{{.Port}}/listenbrainz_ts""" +# for use in playlists admin view +SQLALCHEMY_BINDS = { + 'timescale': SQLALCHEMY_TIMESCALE_URI +} {{end}} {{else}} SQLALCHEMY_TIMESCALE_URI = "SERVICEDOESNOTEXIST_timescale-listenbrainz" TIMESCALE_ADMIN_URI = "SERVICEDOESNOTEXIST_timescale-listenbrainz" TIMESCALE_ADMIN_LB_URI = "SERVICEDOESNOTEXIST_timescale-listenbrainz" +SQLALCHEMY_BINDS = {} {{end}} {{else}} SQLALCHEMY_TIMESCALE_URI = "" TIMESCALE_ADMIN_URI="" TIMESCALE_ADMIN_LB_URI="" +SQLALCHEMY_BINDS = {} {{end}} @@ -101,11 +107,6 @@ MBID_MAPPING_DATABASE_URI = "dbname=musicbrainz_json_dump user=musicbrainz host= MBID_MAPPING_DATABASE_URI = "" {{end}} -# for use in playlists admin view -SQLALCHEMY_BINDS = { - 'timescale': SQLALCHEMY_TIMESCALE_URI -} - {{if service "typesense-listenbrainz-new"}} {{with index (service "typesense-listenbrainz-new") 0}} TYPESENSE_HOST = "{{.Address}}" diff --git a/listenbrainz/webserver/__init__.py b/listenbrainz/webserver/__init__.py index ed994c83ba..d2b1b390dc 100644 --- a/listenbrainz/webserver/__init__.py +++ b/listenbrainz/webserver/__init__.py @@ -187,24 +187,8 @@ def after_request_callbacks(response): return app -def create_web_app(debug=None): - """ Generate a Flask app for LB with all configurations done, connections established and endpoints added.""" - app = create_app(debug=debug) - - # Static files - import listenbrainz.webserver.static_manager - static_manager.read_manifest() - app.static_folder = '/static' - - from listenbrainz.webserver.utils import get_global_props - app.context_processor(lambda: dict( - get_static_path=static_manager.get_static_path, - global_props=get_global_props() - )) - - _register_blueprints(app) - - # Admin views +def init_admin(app): + """Initialize admin interface.""" from listenbrainz import model model.db.init_app(app) @@ -227,8 +211,32 @@ def create_web_app(debug=None): admin.add_view(ExternalServiceAdminView(ExternalServiceModel, model.db.session, endpoint='external_service_model')) admin.add_view(ListensImporterAdminView(ListensImporterModel, model.db.session, endpoint='listens_importer_model')) admin.add_view(ReportedUserAdminView(ReportedUsersModel, model.db.session, endpoint='reported_users_model')) - admin.add_view(PlaylistAdminView(PlaylistModel, model.db.session, endpoint='playlist_model')) - admin.add_view(PlaylistRecordingAdminView(PlaylistRecordingModel, model.db.session, endpoint='playlist_recording_model')) + + # can be empty incase timescale listenstore is down + if app.config['SQLALCHEMY_TIMESCALE_URI']: + # playlist admin views require timescale database, only register if listenstore is available + admin.add_view(PlaylistAdminView(PlaylistModel, model.db.session, endpoint='playlist_model')) + admin.add_view(PlaylistRecordingAdminView(PlaylistRecordingModel, model.db.session, endpoint='playlist_recording_model')) + + +def create_web_app(debug=None): + """ Generate a Flask app for LB with all configurations done, connections established and endpoints added.""" + app = create_app(debug=debug) + + # Static files + import listenbrainz.webserver.static_manager + static_manager.read_manifest() + app.static_folder = '/static' + + from listenbrainz.webserver.utils import get_global_props + app.context_processor(lambda: dict( + get_static_path=static_manager.get_static_path, + global_props=get_global_props() + )) + + _register_blueprints(app) + + init_admin(app) @app.before_request def before_request_gdpr_check():