Cache render_for_web field for alertgroups list serializer (#1236)

# What this PR does
This PR caches the field `render_for_web` with lifetime 1 day and cache
becomes invalid if it was created before
* last alert received
* template changed


## Which issue(s) this PR fixes

## Checklist

- [ ] Tests updated
- [ ] Documentation added
- [ ] `CHANGELOG.md` updated
This commit is contained in:
Ildar Iskhakov 2023-01-28 12:50:41 +08:00 committed by GitHub
parent e0ae9919c7
commit ae44ee5652
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 51 additions and 2 deletions

View file

@ -0,0 +1,18 @@
# Generated by Django 3.2.16 on 2023-01-27 07:41
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('alerts', '0008_alter_alertgrouplogrecord_type'),
]
operations = [
migrations.AddField(
model_name='alertreceivechannel',
name='web_templates_modified_at',
field=models.DateTimeField(blank=True, null=True),
),
]

View file

@ -160,6 +160,7 @@ class AlertReceiveChannel(IntegrationOptionsMixin, MaintainableObject):
web_title_template = models.TextField(null=True, default=None)
web_message_template = models.TextField(null=True, default=None)
web_image_url_template = models.TextField(null=True, default=None)
web_templates_modified_at = models.DateTimeField(blank=True, null=True)
# email related fields are deprecated in favour of messaging backend based templates
# these templates are stored in the messaging_backends_templates field

View file

@ -1,5 +1,7 @@
import logging
from django.core.cache import cache
from django.utils import timezone
from rest_framework import serializers
from apps.alerts.incident_appearance.renderers.classic_markdown_renderer import AlertGroupClassicMarkdownRenderer
@ -13,6 +15,7 @@ from .alert_receive_channel import FastAlertReceiveChannelSerializer
from .user import FastUserSerializer
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
class ShortAlertGroupSerializer(serializers.ModelSerializer):
@ -92,10 +95,33 @@ class AlertGroupListSerializer(EagerLoadingMixin, serializers.ModelSerializer):
if not obj.last_alert:
return {}
return AlertGroupWebRenderer(obj, obj.last_alert).render()
web_templates_modified_at = obj.channel.web_templates_modified_at
last_alert_created_at = obj.last_alert.created_at
CACHE_KEY = f"render_for_web_alert_group_{obj.id}"
CACHE_LIFEIME = 60 * 60 * 24
cached_render_for_web = cache.get(CACHE_KEY, None)
# use cache only if cache exists
# and cache was created after the last alert created
# and either web templates never modified
# or cache was created after templates were modified
if (
cached_render_for_web is not None
and cached_render_for_web.get("cache_created_at") > last_alert_created_at
and (
web_templates_modified_at is None
or cached_render_for_web.get("cache_created_at") > web_templates_modified_at
)
):
render_for_web = cached_render_for_web.get("render_for_web")
else:
render_for_web = AlertGroupWebRenderer(obj, obj.last_alert).render()
cache.set(CACHE_KEY, {"cache_created_at": timezone.now(), "render_for_web": render_for_web}, CACHE_LIFEIME)
return render_for_web
def get_render_for_classic_markdown(self, obj):
# alert group has no alerts
if not obj.last_alert:
return {}

View file

@ -7,6 +7,7 @@ from django.core.exceptions import ObjectDoesNotExist
from django.core.exceptions import ValidationError as DjangoValidationError
from django.core.validators import URLValidator
from django.template.loader import render_to_string
from django.utils import timezone
from jinja2 import TemplateSyntaxError
from rest_framework import serializers
from rest_framework.exceptions import ValidationError
@ -379,6 +380,7 @@ class AlertReceiveChannelTemplatesSerializer(EagerLoadingMixin, serializers.Mode
self.instance.web_title_template = value.strip()
elif default_template is not None and default_template.strip() == value.strip():
self.instance.web_title_template = None
self.instance.web_templates_modified_at = timezone.now()
def get_web_message_template(self, obj):
default_template = AlertReceiveChannel.INTEGRATION_TO_DEFAULT_WEB_MESSAGE_TEMPLATE[obj.integration]
@ -390,6 +392,7 @@ class AlertReceiveChannelTemplatesSerializer(EagerLoadingMixin, serializers.Mode
self.instance.web_message_template = value.strip()
elif default_template is not None and default_template.strip() == value.strip():
self.instance.web_message_template = None
self.instance.web_templates_modified_at = timezone.now()
def get_web_image_url_template(self, obj):
default_template = AlertReceiveChannel.INTEGRATION_TO_DEFAULT_WEB_IMAGE_URL_TEMPLATE[obj.integration]
@ -401,6 +404,7 @@ class AlertReceiveChannelTemplatesSerializer(EagerLoadingMixin, serializers.Mode
self.instance.web_image_url_template = value.strip()
elif default_template is not None and default_template.strip() == value.strip():
self.instance.web_image_url_template = None
self.instance.web_templates_modified_at = timezone.now()
def get_telegram_title_template(self, obj):
default_template = AlertReceiveChannel.INTEGRATION_TO_DEFAULT_TELEGRAM_TITLE_TEMPLATE[obj.integration]