diff --git a/critiquebrainz/db/review.py b/critiquebrainz/db/review.py index 8b8433c8d..ac9b45810 100644 --- a/critiquebrainz/db/review.py +++ b/critiquebrainz/db/review.py @@ -296,14 +296,16 @@ def update(review_id, *, drafted, text=None, rating=None, license_id=None, langu db_revision.update_rating(review_id) result = connection.execute(sqlalchemy.text(""" - SELECT review.entity_id + SELECT review.entity_id, + review.entity_type, + review.user_id FROM review WHERE review.id = :review_id """), { "review_id": review_id, }) review = dict(result.fetchone()) - invalidate_ws_entity_cache(review["entity_id"]) + invalidate_ws_entity_cache(review["entity_id"], review["entity_type"], review["user_id"]) def create(*, entity_id, entity_type, user_id, is_draft, text=None, rating=None, @@ -385,11 +387,11 @@ def create(*, entity_id, entity_type, user_id, is_draft, text=None, rating=None, if rating: db_revision.update_rating(review_id) - invalidate_ws_entity_cache(entity_id) + invalidate_ws_entity_cache(entity_id, entity_type, user_id) return get_by_id(review_id) -def invalidate_ws_entity_cache(entity_id): +def invalidate_ws_entity_cache(entity_id, entity_type, user_id): cache_keys_for_entity_id_key = cache.gen_key('ws_cache', entity_id) cache_keys_to_delete = cache.smembers(cache_keys_for_entity_id_key, namespace=REVIEW_CACHE_NAMESPACE) if cache_keys_to_delete: @@ -402,6 +404,13 @@ def invalidate_ws_entity_cache(entity_id): cache.delete_many(cache_keys_to_delete, namespace=REVIEW_CACHE_NAMESPACE) cache.delete(cache_keys_for_no_entity_id_key, namespace=REVIEW_CACHE_NAMESPACE) + cache_keys_for_top_reviews_key = cache.gen_key('entity_api', entity_type, entity_id, "top_reviews") + cache_keys_for_latest_reviews_key = cache.gen_key('entity_api', entity_type, entity_id, "latest_reviews") + cache_keys_for_user_reviews_key = cache.gen_key('entity_api', entity_id, user_id, "user_reviews") + cache.delete(cache_keys_for_top_reviews_key, namespace=REVIEW_CACHE_NAMESPACE) + cache.delete(cache_keys_for_latest_reviews_key, namespace=REVIEW_CACHE_NAMESPACE) + cache.delete(cache_keys_for_user_reviews_key, namespace=REVIEW_CACHE_NAMESPACE) + # pylint: disable=too-many-branches def get_reviews_list(connection, *, inc_drafts=False, inc_hidden=False, entity_id=None, diff --git a/critiquebrainz/ws/__init__.py b/critiquebrainz/ws/__init__.py index 1bc0afc49..1a4014d69 100644 --- a/critiquebrainz/ws/__init__.py +++ b/critiquebrainz/ws/__init__.py @@ -8,6 +8,8 @@ deploy_env = os.environ.get('DEPLOY_ENV', '') CONSUL_CONFIG_FILE_RETRY_COUNT = 10 REVIEWS_LIMIT = 5 +REVIEW_CACHE_NAMESPACE = "Review" +REVIEW_CACHE_TIMEOUT = 30 * 60 # 30 minutes def create_app(debug=None, config_path=None): diff --git a/critiquebrainz/ws/artist/views.py b/critiquebrainz/ws/artist/views.py index 058fe66d1..8197389d5 100644 --- a/critiquebrainz/ws/artist/views.py +++ b/critiquebrainz/ws/artist/views.py @@ -5,7 +5,8 @@ from critiquebrainz.decorators import crossdomain from critiquebrainz.ws.exceptions import NotFound from critiquebrainz.ws.parser import Parser -from critiquebrainz.ws import REVIEWS_LIMIT +from critiquebrainz.ws import REVIEWS_LIMIT, REVIEW_CACHE_NAMESPACE, REVIEW_CACHE_TIMEOUT +from brainzutils import cache artist_bp = Blueprint('ws_artist', __name__) @@ -229,38 +230,63 @@ def artist_entity_handler(artist_mbid): if not artist: raise NotFound("Can't find an artist with ID: {artist_mbid}".format(artist_mbid=artist_mbid)) + user_review = None + user_id = Parser.uuid('uri', 'user_id', optional=True) if user_id: - user_review, _ = db_review.list_reviews( + user_review_cache_key = cache.gen_key('entity_api', artist['mbid'], user_id, "user_review") + user_review = cache.get(user_review_cache_key) + if not user_review: + user_review, _ = db_review.list_reviews( + entity_id=artist['mbid'], + entity_type='artist', + user_id=user_id + ) + if user_review: + user_review = db_review.to_dict(user_review[0]) + else: + user_review = None + + cache.set(user_review_cache_key, user_review, + expirein=REVIEW_CACHE_TIMEOUT, namespace=REVIEW_CACHE_NAMESPACE) + + ratings_stats, average_rating = db_rating_stats.get_stats(artist_mbid, "artist") + + top_reviews_cache_key = cache.gen_key("entity_api_artist", artist['mbid'], "top_reviews") + top_reviews_cached_result = cache.get(top_reviews_cache_key, REVIEW_CACHE_NAMESPACE) + + if top_reviews_cached_result: + top_reviews, reviews_count = top_reviews_cached_result + else: + top_reviews, reviews_count = db_review.list_reviews( entity_id=artist['mbid'], entity_type='artist', - user_id=user_id + sort='popularity', + limit=REVIEWS_LIMIT, + offset=0, ) - if user_review: - user_review = db_review.to_dict(user_review[0]) - else: - user_review = None + top_reviews = [db_review.to_dict(review) for review in top_reviews] - ratings_stats, average_rating = db_rating_stats.get_stats(artist_mbid, "artist") + cache.set(top_reviews_cache_key, (top_reviews, reviews_count), + expirein=REVIEW_CACHE_TIMEOUT, namespace=REVIEW_CACHE_NAMESPACE) - top_reviews, reviews_count = db_review.list_reviews( - entity_id=artist['mbid'], - entity_type='artist', - sort='popularity', - limit=REVIEWS_LIMIT, - offset=0, - ) + latest_reviews_cache_key = cache.gen_key("entity_api_artist", artist['mbid'], "latest_reviews") + latest_reviews_cached_result = cache.get(latest_reviews_cache_key, REVIEW_CACHE_NAMESPACE) - latest_reviews, reviews_count = db_review.list_reviews( - entity_id=artist['mbid'], - entity_type='artist', - sort='published_on', - limit=REVIEWS_LIMIT, - offset=0, - ) + if latest_reviews_cached_result: + latest_reviews, reviews_count = latest_reviews_cached_result + else: + latest_reviews, reviews_count = db_review.list_reviews( + entity_id=artist['mbid'], + entity_type='artist', + sort='published_on', + limit=REVIEWS_LIMIT, + offset=0, + ) + latest_reviews = [db_review.to_dict(review) for review in latest_reviews] - top_reviews = [db_review.to_dict(review) for review in top_reviews] - latest_reviews = [db_review.to_dict(review) for review in latest_reviews] + cache.set(latest_reviews_cache_key, (latest_reviews, reviews_count), + expirein=REVIEW_CACHE_TIMEOUT, namespace=REVIEW_CACHE_NAMESPACE) result = { "artist": artist, diff --git a/critiquebrainz/ws/bb_author/views.py b/critiquebrainz/ws/bb_author/views.py index 1a9554a7b..26dda70cf 100644 --- a/critiquebrainz/ws/bb_author/views.py +++ b/critiquebrainz/ws/bb_author/views.py @@ -5,7 +5,8 @@ from critiquebrainz.decorators import crossdomain from critiquebrainz.ws.exceptions import NotFound from critiquebrainz.ws.parser import Parser -from critiquebrainz.ws import REVIEWS_LIMIT +from critiquebrainz.ws import REVIEWS_LIMIT, REVIEW_CACHE_NAMESPACE, REVIEW_CACHE_TIMEOUT +from brainzutils import cache author_bp = Blueprint('ws_author', __name__) @@ -166,38 +167,63 @@ def author_entity_handler(author_bbid): if not author: raise NotFound("Can't find an author with ID: {author_bbid}".format(author_bbid=author_bbid)) + user_review = [] + user_id = Parser.uuid('uri', 'user_id', optional=True) if user_id: - user_review, _ = db_review.list_reviews( + user_review_cache_key = cache.gen_key('entity_api', author['bbid'], user_id, "user_review") + user_review = cache.get(user_review_cache_key) + if not user_review: + user_review, _ = db_review.list_reviews( + entity_id=author['bbid'], + entity_type='bb_author', + user_id=user_id + ) + if user_review: + user_review = db_review.to_dict(user_review[0]) + else: + user_review = [] + + cache.set(user_review_cache_key, user_review, + expirein=REVIEW_CACHE_TIMEOUT, namespace=REVIEW_CACHE_NAMESPACE) + + ratings_stats, average_rating = db_rating_stats.get_stats(author_bbid, "bb_author") + + top_reviews_cache_key = cache.gen_key("entity_api_bb_author", author['bbid'], "top_reviews") + top_reviews_cached_result = cache.get(top_reviews_cache_key, REVIEW_CACHE_NAMESPACE) + + if top_reviews_cached_result: + top_reviews, reviews_count = top_reviews_cached_result + else: + top_reviews, reviews_count = db_review.list_reviews( entity_id=author['bbid'], entity_type='bb_author', - user_id=user_id + sort='popularity', + limit=REVIEWS_LIMIT, + offset=0, ) - if user_review: - user_review = db_review.to_dict(user_review[0]) - else: - user_review = None + top_reviews = [db_review.to_dict(review) for review in top_reviews] - ratings_stats, average_rating = db_rating_stats.get_stats(author_bbid, "bb_author") + cache.set(top_reviews_cache_key, (top_reviews, reviews_count), + expirein=REVIEW_CACHE_TIMEOUT, namespace=REVIEW_CACHE_NAMESPACE) + + latest_reviews_cache_key = cache.gen_key("entity_api_bb_author", author['bbid'], "latest_reviews") + latest_reviews_cached_result = cache.get(latest_reviews_cache_key, REVIEW_CACHE_NAMESPACE) + + if latest_reviews_cached_result: + latest_reviews, reviews_count = latest_reviews_cached_result + else: + latest_reviews, reviews_count = db_review.list_reviews( + entity_id=author['bbid'], + entity_type='bb_author', + sort='published_on', + limit=REVIEWS_LIMIT, + offset=0, + ) + latest_reviews = [db_review.to_dict(review) for review in latest_reviews] - top_reviews, reviews_count = db_review.list_reviews( - entity_id=author['bbid'], - entity_type='bb_author', - sort='popularity', - limit=REVIEWS_LIMIT, - offset=0, - ) - - latest_reviews, reviews_count = db_review.list_reviews( - entity_id=author['bbid'], - entity_type='bb_author', - sort='published_on', - limit=REVIEWS_LIMIT, - offset=0, - ) - - top_reviews = [db_review.to_dict(review) for review in top_reviews] - latest_reviews = [db_review.to_dict(review) for review in latest_reviews] + cache.set(latest_reviews_cache_key, (latest_reviews, reviews_count), + expirein=REVIEW_CACHE_TIMEOUT, namespace=REVIEW_CACHE_NAMESPACE) result = { "author": author, diff --git a/critiquebrainz/ws/bb_edition_group/views.py b/critiquebrainz/ws/bb_edition_group/views.py index 54edee1d9..ef12b15cd 100644 --- a/critiquebrainz/ws/bb_edition_group/views.py +++ b/critiquebrainz/ws/bb_edition_group/views.py @@ -5,7 +5,8 @@ from critiquebrainz.decorators import crossdomain from critiquebrainz.ws.exceptions import NotFound from critiquebrainz.ws.parser import Parser -from critiquebrainz.ws import REVIEWS_LIMIT +from critiquebrainz.ws import REVIEWS_LIMIT, REVIEW_CACHE_NAMESPACE, REVIEW_CACHE_TIMEOUT +from brainzutils import cache edition_group_bp = Blueprint('ws_edition_group', __name__) @@ -144,38 +145,63 @@ def edition_group_entity_handler(edition_group_bbid): if not edition_group: raise NotFound("Can't find an edition_group with ID: {edition_group_bbid}".format(edition_group_bbid=edition_group_bbid)) + user_review = [] + user_id = Parser.uuid('uri', 'user_id', optional=True) if user_id: - user_review, _ = db_review.list_reviews( + user_review_cache_key = cache.gen_key('entity_api', edition_group['bbid'], user_id, "user_review") + user_review = cache.get(user_review_cache_key) + if not user_review: + user_review, _ = db_review.list_reviews( + entity_id=edition_group['bbid'], + entity_type='bb_edition_group', + user_id=user_id + ) + if user_review: + user_review = db_review.to_dict(user_review[0]) + else: + user_review = [] + + cache.set(user_review_cache_key, user_review, + expirein=REVIEW_CACHE_TIMEOUT, namespace=REVIEW_CACHE_NAMESPACE) + + ratings_stats, average_rating = db_rating_stats.get_stats(edition_group_bbid, "bb_edition_group") + + top_reviews_cache_key = cache.gen_key("entity_api_bb_edition_group", edition_group['bbid'], "top_reviews") + top_reviews_cached_result = cache.get(top_reviews_cache_key, REVIEW_CACHE_NAMESPACE) + + if top_reviews_cached_result: + top_reviews, reviews_count = top_reviews_cached_result + else: + top_reviews, reviews_count = db_review.list_reviews( entity_id=edition_group['bbid'], entity_type='bb_edition_group', - user_id=user_id + sort='popularity', + limit=REVIEWS_LIMIT, + offset=0, ) - if user_review: - user_review = db_review.to_dict(user_review[0]) - else: - user_review = None + top_reviews = [db_review.to_dict(review) for review in top_reviews] - ratings_stats, average_rating = db_rating_stats.get_stats(edition_group_bbid, "bb_edition_group") + cache.set(top_reviews_cache_key, (top_reviews, reviews_count), + expirein=REVIEW_CACHE_TIMEOUT, namespace=REVIEW_CACHE_NAMESPACE) + + latest_reviews_cache_key = cache.gen_key("entity_api_bb_edition_group", edition_group['bbid'], "latest_reviews") + latest_reviews_cached_result = cache.get(latest_reviews_cache_key, REVIEW_CACHE_NAMESPACE) + + if latest_reviews_cached_result: + latest_reviews, reviews_count = latest_reviews_cached_result + else: + latest_reviews, reviews_count = db_review.list_reviews( + entity_id=edition_group['bbid'], + entity_type='bb_edition_group', + sort='published_on', + limit=REVIEWS_LIMIT, + offset=0, + ) + latest_reviews = [db_review.to_dict(review) for review in latest_reviews] - top_reviews, reviews_count = db_review.list_reviews( - entity_id=edition_group['bbid'], - entity_type='bb_edition_group', - sort='popularity', - limit=REVIEWS_LIMIT, - offset=0, - ) - - latest_reviews, reviews_count = db_review.list_reviews( - entity_id=edition_group['bbid'], - entity_type='bb_edition_group', - sort='published_on', - limit=REVIEWS_LIMIT, - offset=0, - ) - - top_reviews = [db_review.to_dict(review) for review in top_reviews] - latest_reviews = [db_review.to_dict(review) for review in latest_reviews] + cache.set(latest_reviews_cache_key, (latest_reviews, reviews_count), + expirein=REVIEW_CACHE_TIMEOUT, namespace=REVIEW_CACHE_NAMESPACE) result = { "edition_group": edition_group, diff --git a/critiquebrainz/ws/bb_literary_work/views.py b/critiquebrainz/ws/bb_literary_work/views.py index 1c1d006d3..ba0c5991b 100644 --- a/critiquebrainz/ws/bb_literary_work/views.py +++ b/critiquebrainz/ws/bb_literary_work/views.py @@ -5,7 +5,8 @@ from critiquebrainz.decorators import crossdomain from critiquebrainz.ws.exceptions import NotFound from critiquebrainz.ws.parser import Parser -from critiquebrainz.ws import REVIEWS_LIMIT +from critiquebrainz.ws import REVIEWS_LIMIT, REVIEW_CACHE_NAMESPACE, REVIEW_CACHE_TIMEOUT +from brainzutils import cache literary_work_bp = Blueprint('ws_literary_work', __name__) @@ -164,38 +165,63 @@ def literary_work_entity_handler(literary_work_bbid): if not literary_work: raise NotFound("Can't find a literary_work with ID: {literary_work_bbid}".format(literary_work_bbid=literary_work_bbid)) + user_review = [] + user_id = Parser.uuid('uri', 'user_id', optional=True) if user_id: - user_review, _ = db_review.list_reviews( + user_review_cache_key = cache.gen_key('entity_api', literary_work['bbid'], user_id, "user_review") + user_review = cache.get(user_review_cache_key) + if not user_review: + user_review, _ = db_review.list_reviews( + entity_id=literary_work['bbid'], + entity_type='bb_literary_work', + user_id=user_id + ) + if user_review: + user_review = db_review.to_dict(user_review[0]) + else: + user_review = [] + + cache.set(user_review_cache_key, user_review, + expirein=REVIEW_CACHE_TIMEOUT, namespace=REVIEW_CACHE_NAMESPACE) + + ratings_stats, average_rating = db_rating_stats.get_stats(literary_work_bbid, "bb_literary_work") + + top_reviews_cache_key = cache.gen_key("entity_api_bb_literary_work", literary_work['bbid'], "top_reviews") + top_reviews_cached_result = cache.get(top_reviews_cache_key, REVIEW_CACHE_NAMESPACE) + + if top_reviews_cached_result: + top_reviews, reviews_count = top_reviews_cached_result + else: + top_reviews, reviews_count = db_review.list_reviews( entity_id=literary_work['bbid'], entity_type='bb_literary_work', - user_id=user_id + sort='popularity', + limit=REVIEWS_LIMIT, + offset=0, ) - if user_review: - user_review = db_review.to_dict(user_review[0]) - else: - user_review = None + top_reviews = [db_review.to_dict(review) for review in top_reviews] - ratings_stats, average_rating = db_rating_stats.get_stats(literary_work_bbid, "bb_literary_work") + cache.set(top_reviews_cache_key, (top_reviews, reviews_count), + expirein=REVIEW_CACHE_TIMEOUT, namespace=REVIEW_CACHE_NAMESPACE) + + latest_reviews_cache_key = cache.gen_key("entity_api_bb_literary_work", literary_work['bbid'], "latest_reviews") + latest_reviews_cached_result = cache.get(latest_reviews_cache_key, REVIEW_CACHE_NAMESPACE) + + if latest_reviews_cached_result: + latest_reviews, reviews_count = latest_reviews_cached_result + else: + latest_reviews, reviews_count = db_review.list_reviews( + entity_id=literary_work['bbid'], + entity_type='bb_literary_work', + sort='published_on', + limit=REVIEWS_LIMIT, + offset=0, + ) + latest_reviews = [db_review.to_dict(review) for review in latest_reviews] - top_reviews, reviews_count = db_review.list_reviews( - entity_id=literary_work['bbid'], - entity_type='bb_literary_work', - sort='popularity', - limit=REVIEWS_LIMIT, - offset=0, - ) - - latest_reviews, reviews_count = db_review.list_reviews( - entity_id=literary_work['bbid'], - entity_type='bb_literary_work', - sort='published_on', - limit=REVIEWS_LIMIT, - offset=0, - ) - - top_reviews = [db_review.to_dict(review) for review in top_reviews] - latest_reviews = [db_review.to_dict(review) for review in latest_reviews] + cache.set(latest_reviews_cache_key, (latest_reviews, reviews_count), + expirein=REVIEW_CACHE_TIMEOUT, namespace=REVIEW_CACHE_NAMESPACE) result = { "literary_work": literary_work, diff --git a/critiquebrainz/ws/bb_series/views.py b/critiquebrainz/ws/bb_series/views.py index da24edea9..0c20a40c1 100644 --- a/critiquebrainz/ws/bb_series/views.py +++ b/critiquebrainz/ws/bb_series/views.py @@ -5,7 +5,8 @@ from critiquebrainz.decorators import crossdomain from critiquebrainz.ws.exceptions import NotFound from critiquebrainz.ws.parser import Parser -from critiquebrainz.ws import REVIEWS_LIMIT +from critiquebrainz.ws import REVIEWS_LIMIT, REVIEW_CACHE_NAMESPACE, REVIEW_CACHE_TIMEOUT +from brainzutils import cache series_bp = Blueprint('ws_series', __name__) @@ -136,38 +137,63 @@ def series_entity_handler(series_bbid): if not series: raise NotFound("Can't find a series with ID: {series_bbid}".format(series_bbid=series_bbid)) + user_review = [] + user_id = Parser.uuid('uri', 'user_id', optional=True) if user_id: - user_review, _ = db_review.list_reviews( + user_review_cache_key = cache.gen_key('entity_api', series['bbid'], user_id, "user_review") + user_review = cache.get(user_review_cache_key) + if not user_review: + user_review, _ = db_review.list_reviews( + entity_id=series['bbid'], + entity_type='bb_series', + user_id=user_id + ) + if user_review: + user_review = db_review.to_dict(user_review[0]) + else: + user_review = [] + + cache.set(user_review_cache_key, user_review, + expirein=REVIEW_CACHE_TIMEOUT, namespace=REVIEW_CACHE_NAMESPACE) + + ratings_stats, average_rating = db_rating_stats.get_stats(series_bbid, "bb_series") + + top_reviews_cache_key = cache.gen_key("entity_api_bb_series", series['bbid'], "top_reviews") + top_reviews_cached_result = cache.get(top_reviews_cache_key, REVIEW_CACHE_NAMESPACE) + + if top_reviews_cached_result: + top_reviews, reviews_count = top_reviews_cached_result + else: + top_reviews, reviews_count = db_review.list_reviews( entity_id=series['bbid'], entity_type='bb_series', - user_id=user_id + sort='popularity', + limit=REVIEWS_LIMIT, + offset=0, ) - if user_review: - user_review = db_review.to_dict(user_review[0]) - else: - user_review = None + top_reviews = [db_review.to_dict(review) for review in top_reviews] - ratings_stats, average_rating = db_rating_stats.get_stats(series_bbid, "bb_series") + cache.set(top_reviews_cache_key, (top_reviews, reviews_count), + expirein=REVIEW_CACHE_TIMEOUT, namespace=REVIEW_CACHE_NAMESPACE) + + latest_reviews_cache_key = cache.gen_key("entity_api_bb_series", series['bbid'], "latest_reviews") + latest_reviews_cached_result = cache.get(latest_reviews_cache_key, REVIEW_CACHE_NAMESPACE) + + if latest_reviews_cached_result: + latest_reviews, reviews_count = latest_reviews_cached_result + else: + latest_reviews, reviews_count = db_review.list_reviews( + entity_id=series['bbid'], + entity_type='bb_series', + sort='published_on', + limit=REVIEWS_LIMIT, + offset=0, + ) + latest_reviews = [db_review.to_dict(review) for review in latest_reviews] - top_reviews, reviews_count = db_review.list_reviews( - entity_id=series['bbid'], - entity_type='bb_series', - sort='popularity', - limit=REVIEWS_LIMIT, - offset=0, - ) - - latest_reviews, reviews_count = db_review.list_reviews( - entity_id=series['bbid'], - entity_type='bb_series', - sort='published_on', - limit=REVIEWS_LIMIT, - offset=0, - ) - - top_reviews = [db_review.to_dict(review) for review in top_reviews] - latest_reviews = [db_review.to_dict(review) for review in latest_reviews] + cache.set(latest_reviews_cache_key, (latest_reviews, reviews_count), + expirein=REVIEW_CACHE_TIMEOUT, namespace=REVIEW_CACHE_NAMESPACE) result = { "series": series, diff --git a/critiquebrainz/ws/event/views.py b/critiquebrainz/ws/event/views.py index 1404e51a4..6e199dacd 100644 --- a/critiquebrainz/ws/event/views.py +++ b/critiquebrainz/ws/event/views.py @@ -6,6 +6,8 @@ from critiquebrainz.ws.exceptions import NotFound from critiquebrainz.ws.parser import Parser from critiquebrainz.ws import REVIEWS_LIMIT +from critiquebrainz.ws import REVIEWS_LIMIT, REVIEW_CACHE_NAMESPACE, REVIEW_CACHE_TIMEOUT +from brainzutils import cache event_bp = Blueprint('ws_event', __name__) @@ -255,38 +257,63 @@ def event_entity_handler(event_mbid): if not event: raise NotFound("Can't find an event with ID: {event_mbid}".format(event_mbid=event_mbid)) + user_review = None + user_id = Parser.uuid('uri', 'user_id', optional=True) if user_id: - user_review, _ = db_review.list_reviews( + user_review_cache_key = cache.gen_key('entity_api', event['mbid'], user_id, "user_review") + user_review = cache.get(user_review_cache_key) + if not user_review: + user_review, _ = db_review.list_reviews( + entity_id=event['mbid'], + entity_type='event', + user_id=user_id + ) + if user_review: + user_review = db_review.to_dict(user_review[0]) + else: + user_review = None + + cache.set(user_review_cache_key, user_review, + expirein=REVIEW_CACHE_TIMEOUT, namespace=REVIEW_CACHE_NAMESPACE) + + ratings_stats, average_rating = db_rating_stats.get_stats(event_mbid, "event") + + top_reviews_cache_key = cache.gen_key("entity_api_event", event['mbid'], "top_reviews") + top_reviews_cached_result = cache.get(top_reviews_cache_key, REVIEW_CACHE_NAMESPACE) + + if top_reviews_cached_result: + top_reviews, reviews_count = top_reviews_cached_result + else: + top_reviews, reviews_count = db_review.list_reviews( entity_id=event['mbid'], entity_type='event', - user_id=user_id + sort='popularity', + limit=REVIEWS_LIMIT, + offset=0, ) - if user_review: - user_review = db_review.to_dict(user_review[0]) - else: - user_review = None + top_reviews = [db_review.to_dict(review) for review in top_reviews] - ratings_stats, average_rating = db_rating_stats.get_stats(event_mbid, "event") + cache.set(top_reviews_cache_key, (top_reviews, reviews_count), + expirein=REVIEW_CACHE_TIMEOUT, namespace=REVIEW_CACHE_NAMESPACE) - top_reviews, reviews_count = db_review.list_reviews( - entity_id=event['mbid'], - entity_type='event', - sort='popularity', - limit=REVIEWS_LIMIT, - offset=0, - ) + latest_reviews_cache_key = cache.gen_key("entity_api_event", event['mbid'], "latest_reviews") + latest_reviews_cached_result = cache.get(latest_reviews_cache_key, REVIEW_CACHE_NAMESPACE) - latest_reviews, reviews_count = db_review.list_reviews( - entity_id=event['mbid'], - entity_type='event', - sort='published_on', - limit=REVIEWS_LIMIT, - offset=0, - ) + if latest_reviews_cached_result: + latest_reviews, reviews_count = latest_reviews_cached_result + else: + latest_reviews, reviews_count = db_review.list_reviews( + entity_id=event['mbid'], + entity_type='event', + sort='published_on', + limit=REVIEWS_LIMIT, + offset=0, + ) + latest_reviews = [db_review.to_dict(review) for review in latest_reviews] - top_reviews = [db_review.to_dict(review) for review in top_reviews] - latest_reviews = [db_review.to_dict(review) for review in latest_reviews] + cache.set(latest_reviews_cache_key, (latest_reviews, reviews_count), + expirein=REVIEW_CACHE_TIMEOUT, namespace=REVIEW_CACHE_NAMESPACE) result = { "event": event, diff --git a/critiquebrainz/ws/label/views.py b/critiquebrainz/ws/label/views.py index aed63948d..95dd6cf1e 100644 --- a/critiquebrainz/ws/label/views.py +++ b/critiquebrainz/ws/label/views.py @@ -6,6 +6,8 @@ from critiquebrainz.ws.exceptions import NotFound from critiquebrainz.ws.parser import Parser from critiquebrainz.ws import REVIEWS_LIMIT +from critiquebrainz.ws import REVIEWS_LIMIT, REVIEW_CACHE_NAMESPACE, REVIEW_CACHE_TIMEOUT +from brainzutils import cache label_bp = Blueprint('ws_label', __name__) @@ -170,38 +172,63 @@ def label_entity_handler(label_mbid): if not label: raise NotFound("Can't find a label with ID: {label_mbid}".format(label_mbid=label_mbid)) + user_review = None + user_id = Parser.uuid('uri', 'user_id', optional=True) if user_id: - user_review, _ = db_review.list_reviews( + user_review_cache_key = cache.gen_key('entity_api', label['mbid'], user_id, "user_review") + user_review = cache.get(user_review_cache_key) + if not user_review: + user_review, _ = db_review.list_reviews( + entity_id=label['mbid'], + entity_type='label', + user_id=user_id + ) + if user_review: + user_review = db_review.to_dict(user_review[0]) + else: + user_review = None + + cache.set(user_review_cache_key, user_review, + expirein=REVIEW_CACHE_TIMEOUT, namespace=REVIEW_CACHE_NAMESPACE) + + ratings_stats, average_rating = db_rating_stats.get_stats(label_mbid, "label") + + top_reviews_cache_key = cache.gen_key("entity_api_label", label['mbid'], "top_reviews") + top_reviews_cached_result = cache.get(top_reviews_cache_key, REVIEW_CACHE_NAMESPACE) + + if top_reviews_cached_result: + top_reviews, reviews_count = top_reviews_cached_result + else: + top_reviews, reviews_count = db_review.list_reviews( entity_id=label['mbid'], entity_type='label', - user_id=user_id + sort='popularity', + limit=REVIEWS_LIMIT, + offset=0, ) - if user_review: - user_review = db_review.to_dict(user_review[0]) - else: - user_review = None + top_reviews = [db_review.to_dict(review) for review in top_reviews] - ratings_stats, average_rating = db_rating_stats.get_stats(label_mbid, "label") + cache.set(top_reviews_cache_key, (top_reviews, reviews_count), + expirein=REVIEW_CACHE_TIMEOUT, namespace=REVIEW_CACHE_NAMESPACE) + + latest_reviews_cache_key = cache.gen_key("entity_api_label", label['mbid'], "latest_reviews") + latest_reviews_cached_result = cache.get(latest_reviews_cache_key, REVIEW_CACHE_NAMESPACE) + + if latest_reviews_cached_result: + latest_reviews, reviews_count = latest_reviews_cached_result + else: + latest_reviews, reviews_count = db_review.list_reviews( + entity_id=label['mbid'], + entity_type='label', + sort='published_on', + limit=REVIEWS_LIMIT, + offset=0, + ) + latest_reviews = [db_review.to_dict(review) for review in latest_reviews] - top_reviews, reviews_count = db_review.list_reviews( - entity_id=label['mbid'], - entity_type='label', - sort='popularity', - limit=REVIEWS_LIMIT, - offset=0, - ) - - latest_reviews, reviews_count = db_review.list_reviews( - entity_id=label['mbid'], - entity_type='label', - sort='published_on', - limit=REVIEWS_LIMIT, - offset=0, - ) - - top_reviews = [db_review.to_dict(review) for review in top_reviews] - latest_reviews = [db_review.to_dict(review) for review in latest_reviews] + cache.set(latest_reviews_cache_key, (latest_reviews, reviews_count), + expirein=REVIEW_CACHE_TIMEOUT, namespace=REVIEW_CACHE_NAMESPACE) result = { "label": label, diff --git a/critiquebrainz/ws/place/views.py b/critiquebrainz/ws/place/views.py index cd2a0cf1f..ee6d9f909 100644 --- a/critiquebrainz/ws/place/views.py +++ b/critiquebrainz/ws/place/views.py @@ -5,7 +5,8 @@ from critiquebrainz.decorators import crossdomain from critiquebrainz.ws.exceptions import NotFound from critiquebrainz.ws.parser import Parser -from critiquebrainz.ws import REVIEWS_LIMIT +from critiquebrainz.ws import REVIEWS_LIMIT, REVIEW_CACHE_NAMESPACE, REVIEW_CACHE_TIMEOUT +from brainzutils import cache place_bp = Blueprint('ws_place', __name__) @@ -325,38 +326,63 @@ def place_entity_handler(place_mbid): if not place: raise NotFound("Can't find a place with ID: {place_mbid}".format(place_mbid=place_mbid)) + user_review = None + user_id = Parser.uuid('uri', 'user_id', optional=True) if user_id: - user_review, _ = db_review.list_reviews( + user_review_cache_key = cache.gen_key('entity_api', place['mbid'], user_id, "user_review") + user_review = cache.get(user_review_cache_key) + if not user_review: + user_review, _ = db_review.list_reviews( + entity_id=place['mbid'], + entity_type='place', + user_id=user_id + ) + if user_review: + user_review = db_review.to_dict(user_review[0]) + else: + user_review = None + + cache.set(user_review_cache_key, user_review, + expirein=REVIEW_CACHE_TIMEOUT, namespace=REVIEW_CACHE_NAMESPACE) + + ratings_stats, average_rating = db_rating_stats.get_stats(place_mbid, "place") + + top_reviews_cache_key = cache.gen_key("entity_api_place", place['mbid'], "top_reviews") + top_reviews_cached_result = cache.get(top_reviews_cache_key, REVIEW_CACHE_NAMESPACE) + + if top_reviews_cached_result: + top_reviews, reviews_count = top_reviews_cached_result + else: + top_reviews, reviews_count = db_review.list_reviews( entity_id=place['mbid'], entity_type='place', - user_id=user_id + sort='popularity', + limit=REVIEWS_LIMIT, + offset=0, ) - if user_review: - user_review = db_review.to_dict(user_review[0]) - else: - user_review = None + top_reviews = [db_review.to_dict(review) for review in top_reviews] - ratings_stats, average_rating = db_rating_stats.get_stats(place_mbid, "place") + cache.set(top_reviews_cache_key, (top_reviews, reviews_count), + expirein=REVIEW_CACHE_TIMEOUT, namespace=REVIEW_CACHE_NAMESPACE) - top_reviews, reviews_count = db_review.list_reviews( - entity_id=place['mbid'], - entity_type='place', - sort='popularity', - limit=REVIEWS_LIMIT, - offset=0, - ) + latest_reviews_cache_key = cache.gen_key("entity_api_place", place['mbid'], "latest_reviews") + latest_reviews_cached_result = cache.get(latest_reviews_cache_key, REVIEW_CACHE_NAMESPACE) - latest_reviews, reviews_count = db_review.list_reviews( - entity_id=place['mbid'], - entity_type='place', - sort='published_on', - limit=REVIEWS_LIMIT, - offset=0, - ) + if latest_reviews_cached_result: + latest_reviews, reviews_count = latest_reviews_cached_result + else: + latest_reviews, reviews_count = db_review.list_reviews( + entity_id=place['mbid'], + entity_type='place', + sort='published_on', + limit=REVIEWS_LIMIT, + offset=0, + ) + latest_reviews = [db_review.to_dict(review) for review in latest_reviews] - top_reviews = [db_review.to_dict(review) for review in top_reviews] - latest_reviews = [db_review.to_dict(review) for review in latest_reviews] + cache.set(latest_reviews_cache_key, (latest_reviews, reviews_count), + expirein=REVIEW_CACHE_TIMEOUT, namespace=REVIEW_CACHE_NAMESPACE) result = { "place": place, diff --git a/critiquebrainz/ws/recording/views.py b/critiquebrainz/ws/recording/views.py index 28faa6d81..eb2865deb 100644 --- a/critiquebrainz/ws/recording/views.py +++ b/critiquebrainz/ws/recording/views.py @@ -5,7 +5,8 @@ from critiquebrainz.decorators import crossdomain from critiquebrainz.ws.exceptions import NotFound from critiquebrainz.ws.parser import Parser -from critiquebrainz.ws import REVIEWS_LIMIT +from critiquebrainz.ws import REVIEWS_LIMIT, REVIEW_CACHE_NAMESPACE, REVIEW_CACHE_TIMEOUT +from brainzutils import cache recording_bp = Blueprint('ws_recording', __name__) @@ -139,38 +140,63 @@ def recording_entity_handler(recording_mbid): if not recording: raise NotFound("Can't find a recording with ID: {recording_mbid}".format(recording_mbid=recording_mbid)) + user_review = None + user_id = Parser.uuid('uri', 'user_id', optional=True) if user_id: - user_review, _ = db_review.list_reviews( + user_review_cache_key = cache.gen_key('entity_api', recording['mbid'], user_id, "user_review") + user_review = cache.get(user_review_cache_key) + if not user_review: + user_review, _ = db_review.list_reviews( + entity_id=recording['mbid'], + entity_type='recording', + user_id=user_id + ) + if user_review: + user_review = db_review.to_dict(user_review[0]) + else: + user_review = None + + cache.set(user_review_cache_key, user_review, + expirein=REVIEW_CACHE_TIMEOUT, namespace=REVIEW_CACHE_NAMESPACE) + + ratings_stats, average_rating = db_rating_stats.get_stats(recording_mbid, "recording") + + top_reviews_cache_key = cache.gen_key("entity_api_recording", recording['mbid'], "top_reviews") + top_reviews_cached_result = cache.get(top_reviews_cache_key, REVIEW_CACHE_NAMESPACE) + + if top_reviews_cached_result: + top_reviews, reviews_count = top_reviews_cached_result + else: + top_reviews, reviews_count = db_review.list_reviews( entity_id=recording['mbid'], entity_type='recording', - user_id=user_id + sort='popularity', + limit=REVIEWS_LIMIT, + offset=0, ) - if user_review: - user_review = db_review.to_dict(user_review[0]) - else: - user_review = None + top_reviews = [db_review.to_dict(review) for review in top_reviews] - ratings_stats, average_rating = db_rating_stats.get_stats(recording_mbid, "recording") + cache.set(top_reviews_cache_key, (top_reviews, reviews_count), + expirein=REVIEW_CACHE_TIMEOUT, namespace=REVIEW_CACHE_NAMESPACE) + + latest_reviews_cache_key = cache.gen_key("entity_api_recording", recording['mbid'], "latest_reviews") + latest_reviews_cached_result = cache.get(latest_reviews_cache_key, REVIEW_CACHE_NAMESPACE) + + if latest_reviews_cached_result: + latest_reviews, reviews_count = latest_reviews_cached_result + else: + latest_reviews, reviews_count = db_review.list_reviews( + entity_id=recording['mbid'], + entity_type='recording', + sort='published_on', + limit=REVIEWS_LIMIT, + offset=0, + ) + latest_reviews = [db_review.to_dict(review) for review in latest_reviews] - top_reviews, reviews_count = db_review.list_reviews( - entity_id=recording['mbid'], - entity_type='recording', - sort='popularity', - limit=REVIEWS_LIMIT, - offset=0, - ) - - latest_reviews, reviews_count = db_review.list_reviews( - entity_id=recording['mbid'], - entity_type='recording', - sort='published_on', - limit=REVIEWS_LIMIT, - offset=0, - ) - - top_reviews = [db_review.to_dict(review) for review in top_reviews] - latest_reviews = [db_review.to_dict(review) for review in latest_reviews] + cache.set(latest_reviews_cache_key, (latest_reviews, reviews_count), + expirein=REVIEW_CACHE_TIMEOUT, namespace=REVIEW_CACHE_NAMESPACE) result = { "recording": recording, diff --git a/critiquebrainz/ws/release_group/views.py b/critiquebrainz/ws/release_group/views.py index 3c2485a81..062e38b9c 100644 --- a/critiquebrainz/ws/release_group/views.py +++ b/critiquebrainz/ws/release_group/views.py @@ -5,7 +5,8 @@ from critiquebrainz.decorators import crossdomain from critiquebrainz.ws.exceptions import NotFound from critiquebrainz.ws.parser import Parser -from critiquebrainz.ws import REVIEWS_LIMIT +from critiquebrainz.ws import REVIEWS_LIMIT, REVIEW_CACHE_NAMESPACE, REVIEW_CACHE_TIMEOUT +from brainzutils import cache release_group_bp = Blueprint('ws_release_group', __name__) @@ -152,38 +153,63 @@ def release_group_entity_handler(release_group_mbid): if not release_group: raise NotFound("Can't find a release group with ID: {release_group_mbid}".format(release_group_mbid=release_group_mbid)) + user_review = None + user_id = Parser.uuid('uri', 'user_id', optional=True) if user_id: - user_review, _ = db_review.list_reviews( + user_review_cache_key = cache.gen_key('entity_api', release_group['mbid'], user_id, "user_review") + user_review = cache.get(user_review_cache_key) + if not user_review: + user_review, _ = db_review.list_reviews( + entity_id=release_group['mbid'], + entity_type='release_group', + user_id=user_id + ) + if user_review: + user_review = db_review.to_dict(user_review[0]) + else: + user_review = None + + cache.set(user_review_cache_key, user_review, + expirein=REVIEW_CACHE_TIMEOUT, namespace=REVIEW_CACHE_NAMESPACE) + + ratings_stats, average_rating = db_rating_stats.get_stats(release_group_mbid, "release_group") + + top_reviews_cache_key = cache.gen_key("entity_api_release_group", release_group['mbid'], "top_reviews") + top_reviews_cached_result = cache.get(top_reviews_cache_key, REVIEW_CACHE_NAMESPACE) + + if top_reviews_cached_result: + top_reviews, reviews_count = top_reviews_cached_result + else: + top_reviews, reviews_count = db_review.list_reviews( entity_id=release_group['mbid'], entity_type='release_group', - user_id=user_id + sort='popularity', + limit=REVIEWS_LIMIT, + offset=0, ) - if user_review: - user_review = db_review.to_dict(user_review[0]) - else: - user_review = None + top_reviews = [db_review.to_dict(review) for review in top_reviews] - ratings_stats, average_rating = db_rating_stats.get_stats(release_group_mbid, "release_group") + cache.set(top_reviews_cache_key, (top_reviews, reviews_count), + expirein=REVIEW_CACHE_TIMEOUT, namespace=REVIEW_CACHE_NAMESPACE) + + latest_reviews_cache_key = cache.gen_key("entity_api_release_group", release_group['mbid'], "latest_reviews") + latest_reviews_cached_result = cache.get(latest_reviews_cache_key, REVIEW_CACHE_NAMESPACE) + + if latest_reviews_cached_result: + latest_reviews, reviews_count = latest_reviews_cached_result + else: + latest_reviews, reviews_count = db_review.list_reviews( + entity_id=release_group['mbid'], + entity_type='release_group', + sort='published_on', + limit=REVIEWS_LIMIT, + offset=0, + ) + latest_reviews = [db_review.to_dict(review) for review in latest_reviews] - top_reviews, reviews_count = db_review.list_reviews( - entity_id=release_group['mbid'], - entity_type='release_group', - sort='popularity', - limit=REVIEWS_LIMIT, - offset=0, - ) - - latest_reviews, reviews_count = db_review.list_reviews( - entity_id=release_group['mbid'], - entity_type='release_group', - sort='published_on', - limit=REVIEWS_LIMIT, - offset=0, - ) - - top_reviews = [db_review.to_dict(review) for review in top_reviews] - latest_reviews = [db_review.to_dict(review) for review in latest_reviews] + cache.set(latest_reviews_cache_key, (latest_reviews, reviews_count), + expirein=REVIEW_CACHE_TIMEOUT, namespace=REVIEW_CACHE_NAMESPACE) result = { "release_group": release_group, diff --git a/critiquebrainz/ws/work/views.py b/critiquebrainz/ws/work/views.py index af9784b71..510a36e85 100644 --- a/critiquebrainz/ws/work/views.py +++ b/critiquebrainz/ws/work/views.py @@ -5,7 +5,9 @@ from critiquebrainz.decorators import crossdomain from critiquebrainz.ws.exceptions import NotFound from critiquebrainz.ws.parser import Parser -from critiquebrainz.ws import REVIEWS_LIMIT +from critiquebrainz.ws import REVIEWS_LIMIT, REVIEW_CACHE_NAMESPACE, REVIEW_CACHE_TIMEOUT +from brainzutils import cache + work_bp = Blueprint('ws_work', __name__) @@ -214,38 +216,63 @@ def work_entity_handler(work_mbid): if not work: raise NotFound("Can't find a work with ID: {work_mbid}".format(work_mbid=work_mbid)) + user_review = None + user_id = Parser.uuid('uri', 'user_id', optional=True) if user_id: - user_review, _ = db_review.list_reviews( + user_review_cache_key = cache.gen_key('entity_api', work['mbid'], user_id, "user_review") + user_review = cache.get(user_review_cache_key) + if not user_review: + user_review, _ = db_review.list_reviews( + entity_id=work['mbid'], + entity_type='work', + user_id=user_id + ) + if user_review: + user_review = db_review.to_dict(user_review[0]) + else: + user_review = None + + cache.set(user_review_cache_key, user_review, + expirein=REVIEW_CACHE_TIMEOUT, namespace=REVIEW_CACHE_NAMESPACE) + + ratings_stats, average_rating = db_rating_stats.get_stats(work_mbid, "work") + + top_reviews_cache_key = cache.gen_key("entity_api_work", work['mbid'], "top_reviews") + top_reviews_cached_result = cache.get(top_reviews_cache_key, REVIEW_CACHE_NAMESPACE) + + if top_reviews_cached_result: + top_reviews, reviews_count = top_reviews_cached_result + else: + top_reviews, reviews_count = db_review.list_reviews( entity_id=work['mbid'], entity_type='work', - user_id=user_id + sort='popularity', + limit=REVIEWS_LIMIT, + offset=0, ) - if user_review: - user_review = db_review.to_dict(user_review[0]) - else: - user_review = None + top_reviews = [db_review.to_dict(review) for review in top_reviews] - ratings_stats, average_rating = db_rating_stats.get_stats(work_mbid, "work") + cache.set(top_reviews_cache_key, (top_reviews, reviews_count), + expirein=REVIEW_CACHE_TIMEOUT, namespace=REVIEW_CACHE_NAMESPACE) - top_reviews, reviews_count = db_review.list_reviews( - entity_id=work['mbid'], - entity_type='work', - sort='popularity', - limit=REVIEWS_LIMIT, - offset=0, - ) + latest_reviews_cache_key = cache.gen_key("entity_api_work", work['mbid'], "latest_reviews") + latest_reviews_cached_result = cache.get(latest_reviews_cache_key, REVIEW_CACHE_NAMESPACE) - latest_reviews, reviews_count = db_review.list_reviews( - entity_id=work['mbid'], - entity_type='work', - sort='published_on', - limit=REVIEWS_LIMIT, - offset=0, - ) + if latest_reviews_cached_result: + latest_reviews, reviews_count = latest_reviews_cached_result + else: + latest_reviews, reviews_count = db_review.list_reviews( + entity_id=work['mbid'], + entity_type='work', + sort='published_on', + limit=REVIEWS_LIMIT, + offset=0, + ) + latest_reviews = [db_review.to_dict(review) for review in latest_reviews] - top_reviews = [db_review.to_dict(review) for review in top_reviews] - latest_reviews = [db_review.to_dict(review) for review in latest_reviews] + cache.set(latest_reviews_cache_key, (latest_reviews, reviews_count), + expirein=REVIEW_CACHE_TIMEOUT, namespace=REVIEW_CACHE_NAMESPACE) result = { "work": work,