mirror of
https://github.com/GSA/notifications-api.git
synced 2026-07-17 21:20:59 -04:00
Cache template when posting a notification
This commit proposes two types of caching to speed up the post notification processing time. Since every notification needs a template, if we can avoid going to the db to get the template then this should be faster. The first cache is an LRU cache, which means that, for a given `template_id`, `service_id` and `version` the app will go to memory rather than the database to get the template. This should be much faster, and we should be guaranteed that a combination of those three parameters should always return the same result. But, we don’t know the template version at the time of making the call. So this commit also adds another layer of caching to find the most recent version number of a template. Since this can be changed by other instances we need to cache it externally, so this cache uses Redis. Redis will be a lot slower than going to memory, but hopefully quicker than going to the database. By only caching the minimal amount of data possible in Redis (just the version as a number) we’re hopefully minimising the performance hit from going to an external service.
This commit is contained in:
@@ -1,10 +1,12 @@
|
||||
from datetime import datetime
|
||||
from functools import lru_cache
|
||||
import uuid
|
||||
|
||||
from flask import current_app
|
||||
from sqlalchemy import asc, desc
|
||||
from sqlalchemy import asc, desc, func
|
||||
from sqlalchemy.orm.exc import NoResultFound
|
||||
|
||||
from app import db
|
||||
from app import db, redis_store
|
||||
from app.models import (
|
||||
LETTER_TYPE,
|
||||
SECOND_CLASS,
|
||||
@@ -20,6 +22,9 @@ from app.dao.dao_utils import (
|
||||
from app.dao.users_dao import get_user_by_id
|
||||
|
||||
|
||||
SEVEN_DAYS_IN_SECONDS = 604_800
|
||||
|
||||
|
||||
@transactional
|
||||
@version_class(
|
||||
VersionOptions(Template, history_class=TemplateHistory)
|
||||
@@ -49,7 +54,7 @@ def dao_create_template(template):
|
||||
def dao_update_template(template):
|
||||
if template.archived:
|
||||
template.folder = None
|
||||
|
||||
redis_store.delete(f'template-{template.id}-version')
|
||||
db.session.add(template)
|
||||
|
||||
|
||||
@@ -92,6 +97,33 @@ def dao_redact_template(template, user_id):
|
||||
db.session.add(template.template_redacted)
|
||||
|
||||
|
||||
def dao_get_template_version(template_id):
|
||||
|
||||
cache_key = f'template-{template_id}-version'
|
||||
version = redis_store.get(cache_key)
|
||||
|
||||
if not version:
|
||||
|
||||
version = db.session.query(
|
||||
func.max(TemplateHistory.version)
|
||||
).filter_by(
|
||||
id=template_id,
|
||||
hidden=False,
|
||||
).scalar()
|
||||
|
||||
if not version:
|
||||
raise NoResultFound
|
||||
|
||||
redis_store.set(cache_key, version, ex=SEVEN_DAYS_IN_SECONDS)
|
||||
|
||||
return version
|
||||
|
||||
|
||||
@lru_cache(maxsize=1024)
|
||||
def dao_get_template_by_id_and_service_id_and_version(*, template_id, service_id, version):
|
||||
return dao_get_template_by_id_and_service_id(template_id, service_id, version)
|
||||
|
||||
|
||||
def dao_get_template_by_id_and_service_id(template_id, service_id, version=None):
|
||||
if version is not None:
|
||||
return TemplateHistory.query.filter_by(
|
||||
|
||||
@@ -140,9 +140,10 @@ def check_notification_content_is_not_empty(template_with_content):
|
||||
|
||||
def validate_template(template_id, personalisation, service, notification_type):
|
||||
try:
|
||||
template = templates_dao.dao_get_template_by_id_and_service_id(
|
||||
template = templates_dao.dao_get_template_by_id_and_service_id_and_version(
|
||||
template_id=template_id,
|
||||
service_id=service.id
|
||||
service_id=service.id,
|
||||
version=templates_dao.dao_get_template_version(template_id),
|
||||
)
|
||||
except NoResultFound:
|
||||
message = 'Template not found'
|
||||
|
||||
Reference in New Issue
Block a user