Skip to content

Commit 9489d95

Browse files
authored
Merge pull request #4643 from nhsuk/cache-navigation-header-counts
Cache navigation header counts
2 parents 67282d4 + e16ebb8 commit 9489d95

File tree

14 files changed

+148
-24
lines changed

14 files changed

+148
-24
lines changed

Gemfile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,13 +48,14 @@ gem "jwt"
4848
gem "mechanize"
4949
gem "notifications-ruby-client"
5050
gem "okcomputer"
51-
gem "omniauth_openid_connect"
5251
gem "omniauth-rails_csrf_protection"
52+
gem "omniauth_openid_connect"
5353
gem "pagy"
5454
gem "phonelib"
5555
gem "pundit"
5656
gem "rails_semantic_logger"
5757
gem "rainbow"
58+
gem "redis"
5859
gem "ruby-progressbar"
5960
gem "rubyzip"
6061
gem "sentry-rails"

Gemfile.lock

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -519,6 +519,8 @@ GEM
519519
erb
520520
psych (>= 4.0.0)
521521
redcarpet (3.6.1)
522+
redis (5.4.1)
523+
redis-client (>= 0.22.0)
522524
redis-client (0.25.2)
523525
connection_pool
524526
redis-prescription (2.6.0)
@@ -819,6 +821,7 @@ DEPENDENCIES
819821
rails (~> 8.0.2)
820822
rails_semantic_logger
821823
rainbow
824+
redis
822825
rladr
823826
rspec
824827
rspec-html-matchers

app/components/app_imports_navigation_component.rb

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
# frozen_string_literal: true
22

33
class AppImportsNavigationComponent < ViewComponent::Base
4-
def initialize(active:)
4+
def initialize(active:, team:)
55
@active = active
6+
@team = team
67
end
78

89
def call
@@ -31,18 +32,22 @@ def call
3132

3233
private
3334

34-
attr_reader :active
35+
attr_reader :active, :team
3536

36-
delegate :import_issues_count, :policy, :policy_scope, to: :helpers
37+
delegate :policy, :policy_scope, to: :helpers
3738

3839
def issues_text
39-
safe_join(
40-
["Import issues", " ", render(AppCountComponent.new(import_issues_count))]
41-
)
40+
count = TeamCachedCounts.new(team).import_issues
41+
text_with_count("Import issues", count)
4242
end
4343

4444
def notices_text
4545
count = ImportantNotices.call(patient_scope: policy_scope(Patient)).length
46-
safe_join(["Important notices", " ", render(AppCountComponent.new(count))])
46+
47+
text_with_count("Important notices", count)
48+
end
49+
50+
def text_with_count(text, count)
51+
safe_join([text, " ", render(AppCountComponent.new(count))])
4752
end
4853
end

app/controllers/parent_interface/consent_forms_controller.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@ def record
5555

5656
session.delete(:consent_form_id)
5757

58+
TeamCachedCounts.new(@team).reset_unmatched_consent_responses!
59+
5860
send_consent_form_confirmation(@consent_form)
5961

6062
ConsentFormMatchingJob.perform_later(@consent_form)

app/helpers/application_helper.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,4 +57,6 @@ def manifest_link_tag(name, **options)
5757
def opengraph_image_tag(service_url, name)
5858
tag.meta(property: "og:image", content: "#{service_url}#{asset_path(name)}")
5959
end
60+
61+
def cached_counts = TeamCachedCounts.new(current_team)
6062
end

app/helpers/imports_helper.rb

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,6 @@ module ImportsHelper
1212
%w[registration] => :registration
1313
}.freeze
1414

15-
def import_issues_count
16-
vaccination_records_with_issues =
17-
policy_scope(VaccinationRecord).with_pending_changes.pluck(:patient_id)
18-
19-
patients_with_issues = policy_scope(Patient).with_pending_changes.pluck(:id)
20-
21-
(vaccination_records_with_issues + patients_with_issues).uniq.length
22-
end
23-
2415
def issue_categories_for(pending_changes)
2516
FIELD_GROUPS.filter_map do |(keys, group)|
2617
group.to_s.humanize if (pending_changes & keys).any?

app/jobs/commit_patient_changesets_job.rb

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ def perform(import)
2929

3030
import.postprocess_rows!
3131

32+
reset_counts(import)
33+
3234
import.update_columns(
3335
processed_at: Time.zone.now,
3436
status: :processed,
@@ -165,4 +167,10 @@ def has_auto_confirmable_school_move?(school_move, import)
165167
academic_year: import.academic_year
166168
) || school_move.patient.archived?(team: import.team)
167169
end
170+
171+
def reset_counts(import)
172+
cached_counts = TeamCachedCounts.new(import.team)
173+
cached_counts.reset_import_issues!
174+
cached_counts.reset_school_moves!
175+
end
168176
end

app/jobs/consent_form_matching_job.rb

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@ def match_with_exact_nhs_number
5959
patient.update_from_pds!(pds_patient)
6060
send_parental_contact_warning_if_needed(patient, @consent_form)
6161
@consent_form.match_with_patient!(patient, current_user: nil)
62+
reset_counts
63+
true
6264
end
6365

6466
def session_patients
@@ -95,5 +97,10 @@ def match_patient(patient)
9597

9698
send_parental_contact_warning_if_needed(patient, @consent_form)
9799
@consent_form.match_with_patient!(patient, current_user: nil)
100+
reset_counts
101+
end
102+
103+
def reset_counts
104+
TeamCachedCounts.new(@consent_form.team).reset_unmatched_consent_responses!
98105
end
99106
end

app/lib/team_cached_counts.rb

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
# frozen_string_literal: true
2+
3+
class TeamCachedCounts
4+
def initialize(team)
5+
@team = team
6+
end
7+
8+
def import_issues
9+
return nil if current_user.nil?
10+
11+
Rails
12+
.cache
13+
.fetch(import_issues_key) do
14+
vaccination_records_with_issues =
15+
VaccinationRecordPolicy::Scope
16+
.new(current_user, VaccinationRecord)
17+
.resolve
18+
.with_pending_changes
19+
.pluck(:patient_id)
20+
21+
patients_with_issues =
22+
PatientPolicy::Scope
23+
.new(current_user, Patient)
24+
.resolve
25+
.with_pending_changes
26+
.pluck(:id)
27+
28+
(vaccination_records_with_issues + patients_with_issues).uniq.length
29+
end
30+
end
31+
32+
def reset_import_issues!
33+
Rails.cache.delete(import_issues_key)
34+
end
35+
36+
def school_moves
37+
return nil if current_user.nil?
38+
39+
Rails
40+
.cache
41+
.fetch(school_moves_key) do
42+
SchoolMovePolicy::Scope.new(current_user, SchoolMove).resolve.count
43+
end
44+
end
45+
46+
def reset_school_moves!
47+
Rails.cache.delete(school_moves_key)
48+
end
49+
50+
def unmatched_consent_responses
51+
return nil if current_user.nil?
52+
53+
Rails
54+
.cache
55+
.fetch(unmatched_consent_responses_key) do
56+
ConsentFormPolicy::Scope
57+
.new(current_user, ConsentForm)
58+
.resolve
59+
.unmatched
60+
.recorded
61+
.not_archived
62+
.count
63+
end
64+
end
65+
66+
def reset_unmatched_consent_responses!
67+
Rails.cache.delete(unmatched_consent_responses_key)
68+
end
69+
70+
private
71+
72+
attr_reader :team
73+
74+
def import_issues_key = cache_key("import-issues")
75+
76+
def school_moves_key = cache_key("school-moves")
77+
78+
def unmatched_consent_responses_key = cache_key("unmatched-consent-responses")
79+
80+
def current_user
81+
# We can't use the policy_scope helper here as we're not in a controller.
82+
# Instead, we can mock what a `User` looks like from the perspective of a
83+
# controller to satisfy the policy scopes.
84+
@current_user ||=
85+
if team && (organisation = team.organisation)
86+
OpenStruct.new(selected_team: team, selected_organisation: organisation)
87+
end
88+
end
89+
90+
def cache_key(type) = "cached-counts/#{type}/#{team.id}"
91+
end

app/views/imports/index.html.erb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,6 @@
22

33
<%= govuk_button_to "Import records", imports_path, secondary: true, class: "nhsuk-u-margin-bottom-4" %>
44

5-
<%= render AppImportsNavigationComponent.new(active: :index) %>
5+
<%= render AppImportsNavigationComponent.new(active: :index, team: current_team) %>
66

77
<%= render AppImportsTableComponent.new(team: current_team) %>

0 commit comments

Comments
 (0)