Cache organisation name in Redis

A lot of pages in the admin app are now generated entirely from Redis,
without touching the API.

The one remaining API call that a lot of pages make, when the user is
platform admin or a member of an organisation, is to get the name of
the current service’s organisation.

This commit adds some code to start caching that as well, which should
speed up page load times for when we’re clicking around the admin app
(it’s typically 100ms just to get the organisation, and more than that
when the API is under load).

This means changing the service model to get the organisation from the
API by ID, not by service ID. Otherwise it would be very hard to clear
the cache if the name of the organisation ever changed.

We can’t cache the whole organisation because it has a
`count_of_live_services` field which can change at any time, without an
update being made.
This commit is contained in:
Chris Hill-Scott
2020-03-20 08:42:33 +00:00
parent c448eb8995
commit cc5701e870
19 changed files with 264 additions and 131 deletions

View File

@@ -428,6 +428,7 @@ def clear_cache():
'organisations',
'domains',
'live-service-and-organisation-counts',
'organisation-????????-????-????-????-????????????-name',
]),
])

View File

@@ -991,15 +991,14 @@ def service_preview_letter_branding(service_id):
def link_service_to_organisation(service_id):
all_organisations = organisations_client.get_organisations()
current_linked_organisation = organisations_client.get_service_organisation(service_id).get('id', None)
form = LinkOrganisationsForm(
choices=convert_dictionary_to_wtforms_choices_format(all_organisations, 'id', 'name'),
organisations=current_linked_organisation
organisations=current_service.organisation_id
)
if form.validate_on_submit():
if form.organisations.data != current_linked_organisation:
if form.organisations.data != current_service.organisation_id:
organisations_client.update_service_organisation(
service_id,
form.organisations.data

View File

@@ -50,6 +50,8 @@ class Organisation(JSONModel):
@classmethod
def from_id(cls, org_id):
if not org_id:
return cls({})
return cls(organisations_client.get_organisation(org_id))
@classmethod

View File

@@ -18,6 +18,7 @@ from app.notify_client.inbound_number_client import inbound_number_client
from app.notify_client.invite_api_client import invite_api_client
from app.notify_client.job_api_client import job_api_client
from app.notify_client.letter_branding_client import letter_branding_client
from app.notify_client.organisations_api_client import organisations_client
from app.notify_client.service_api_client import service_api_client
from app.notify_client.template_folder_api_client import (
template_folder_api_client,
@@ -459,7 +460,7 @@ class Service(JSONModel):
@cached_property
def organisation(self):
return Organisation.from_service(self.id)
return Organisation.from_id(self.organisation_id)
@property
def organisation_id(self):
@@ -469,6 +470,12 @@ class Service(JSONModel):
def organisation_type(self):
return self.organisation.organisation_type or self._dict['organisation_type']
@property
def organisation_name(self):
if not self.organisation:
return None
return organisations_client.get_organisation_name(self.organisation_id)
@property
def organisation_type_label(self):
return dict(Organisation.TYPES).get(self.organisation_type)

View File

@@ -22,6 +22,10 @@ class OrganisationsClient(NotifyAdminAPIClient):
def get_organisation(self, org_id):
return self.get(url='/organisations/{}'.format(org_id))
@cache.set('organisation-{org_id}-name')
def get_organisation_name(self, org_id):
return self.get_organisation(org_id)['name']
def get_organisation_by_domain(self, domain):
try:
return self.get(
@@ -54,6 +58,7 @@ class OrganisationsClient(NotifyAdminAPIClient):
return api_response
@cache.delete('organisation-{org_id}-name')
def update_organisation_name(self, org_id, name):
return self.update_organisation(org_id, name=name)

View File

@@ -316,7 +316,7 @@
{% call field() %}
{% if current_service.organisation_id %}
<a class="govuk-link govuk-link--no-visited-state" href="{{ url_for('main.organisation_dashboard', org_id=current_service.organisation_id) }}">
{{ current_service.organisation.name }}
{{ current_service.organisation_name }}
</a>
{% else %}
<span class="table-field-status-default">Not set</span>

View File

@@ -12,7 +12,7 @@
{% if current_service.organisation_id %}
{% if current_user.platform_admin or
(current_user.belongs_to_organisation(current_service.organisation_id) and current_service.live) %}
<a href="{{ url_for('.organisation_dashboard', org_id=current_service.organisation_id) }}" class="govuk-link govuk-link--no-visited-state navigation-organisation-link">{{ current_service.organisation.name }}</a>
<a href="{{ url_for('.organisation_dashboard', org_id=current_service.organisation_id) }}" class="govuk-link govuk-link--no-visited-state navigation-organisation-link">{{ current_service.organisation_name }}</a>
{% endif %}
{% endif %}
<div class="navigation-service-name govuk-!-font-weight-bold">