Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
66 commits
Select commit Hold shift + click to select a range
21c748e
Basic implementation of valkey with a connected sidekiq service
TheOneFromNorway Jun 11, 2025
8277d5e
Add necessary deployment permissions
TheOneFromNorway Aug 13, 2025
c229b8f
Finalize valkey config
TheOneFromNorway Aug 14, 2025
a210399
Enable PDS lookup during import for patient import
misaka Aug 15, 2025
9e3ba3a
Search for patient if an NHS number isn't provided
misaka Aug 15, 2025
3bf3b73
Auto-save new nhs numbers on import
misaka Aug 15, 2025
ab018d6
Use VaccinationStatus model rather than converting to hash
thomasleese Aug 15, 2025
f16f6f5
Ensure we handle a triage not existing
thomasleese Aug 15, 2025
4b9c887
Update content on "Do not vaccinate"
thomasleese Aug 15, 2025
f0d9baf
Update extravaganza test for PDS search only
murugapl Aug 15, 2025
605b88b
Merge pull request #4292 from nhsuk/vaccination-programmes-improvements
thomasleese Aug 15, 2025
dadbc87
Merge pull request #3809 from nhsuk/create_valkey_config_for_sidekiq
TheOneFromNorway Aug 15, 2025
8a0517f
Install sidekiq and sidekiq-throttled
thomasleese Aug 13, 2025
cb2f98b
Rename NHSAPIConcurrencyConcern
thomasleese Aug 13, 2025
0b7e3fd
Increase database pool for Sidekiq
thomasleese Aug 13, 2025
bef055c
Add Sidekiq configuration
thomasleese Aug 13, 2025
5af5df2
Run Sidekiq server
thomasleese Aug 13, 2025
520a34c
Don't customise PDS job queue
thomasleese Aug 13, 2025
85f5cb4
Don't schedule PDS jobs with gaps
thomasleese Aug 13, 2025
1799930
Use Sidekiq for PDS jobs
thomasleese Aug 13, 2025
d09c4c9
Rename job throttling concerns
thomasleese Aug 14, 2025
25926fd
Add Sidekiq monitoring
thomasleese Aug 13, 2025
73241c5
Pass programme to StatusGenerator::Session
thomasleese Aug 15, 2025
96ba258
Pass patient to StatusGenerator::Session
thomasleese Aug 15, 2025
1057e19
Use StatusGenerator::Consent
thomasleese Aug 15, 2025
78c8df4
Add conflicting session status
thomasleese Aug 15, 2025
47f4eac
Remove team migration scripts
thomasleese Aug 15, 2025
61a2906
Merge pull request #4265 from nhsuk/sidekiq-pds
thomasleese Aug 15, 2025
ff77e6d
Change to default academic year preparation period
thomasleese Aug 15, 2025
46f65cb
Add missing newlines at ends of file
thomasleese Aug 15, 2025
83b05ed
Increase PDS rate limit to 50 req/s
thomasleese Aug 15, 2025
a5db9a7
Merge pull request #4295 from nhsuk/remove-team-migration
thomasleese Aug 15, 2025
ce8e643
Merge pull request #4294 from nhsuk/conflicting-session-status
thomasleese Aug 15, 2025
2118429
Merge pull request #4296 from nhsuk/pds-rate-limit
thomasleese Aug 15, 2025
2678fbb
Merge pull request #4291 from nhsuk/simplify-pds-update-during-import
thomasleese Aug 15, 2025
ec60f2b
Bump rubocop-govuk from 5.1.19 to 5.1.20
dependabot[bot] Aug 15, 2025
60828af
Fix bug where parents weren't being imported correctly
murugapl Aug 16, 2025
95ee0b8
Merge pull request #4298 from nhsuk/dependabot/bundler/next/rubocop-g…
thomasleese Aug 16, 2025
db62e20
Extend import feature tests to cover parent and school move functiona…
murugapl Aug 16, 2025
795defc
Disable PDS search during class imports if postcode isnt present
murugapl Aug 17, 2025
41d5831
Merge pull request #4299 from nhsuk/fix-patient-changeset-bugs
murugapl Aug 18, 2025
bf3caa7
Remove `health_questions:add`
thomasleese Aug 16, 2025
5904203
Remove `vaccination_records:update_notify_parents`
thomasleese Aug 16, 2025
99e90fc
Remove `performance:generate`
thomasleese Aug 16, 2025
66140aa
Use `bin/rspec` instead of `bin/bundle exec rspec`
thomasleese Aug 16, 2025
b312183
Rename `prepare_ignore_concurrent_migration_exceptions.rake`
thomasleese Aug 16, 2025
04ba991
Rename `serviceworker_precompile.rake`
thomasleese Aug 16, 2025
7938705
Move `generate` and `stats` to `app/lib`
thomasleese Aug 16, 2025
4465cc5
Replace `access_log` Rake task with CLI command
thomasleese Aug 16, 2025
1ac394a
Replace `consent_forms:generator` Rake task with CLI command
thomasleese Aug 16, 2025
66c9909
Replace `gp_practices:import` Rake task with CLI command
thomasleese Aug 16, 2025
7ac8e0c
Replace `nhs_api:access_token` Rake task with CLI command
thomasleese Aug 16, 2025
420ddaa
Replace `pds:patients` Rake tasks with CLI command
thomasleese Aug 16, 2025
b4b321f
Replace `schools:move_patients` Rake task with CLI command
thomasleese Aug 16, 2025
2d67871
Replace `subteams:create` Rake task with CLI command
thomasleese Aug 16, 2025
b639408
Replace `users:create` Rake task with CLI command
thomasleese Aug 16, 2025
88fe9de
Combine smoke testing Rake tasks
thomasleese Aug 16, 2025
2abaae7
Merge pull request #4300 from nhsuk/rake-to-cli
thomasleese Aug 18, 2025
08597e2
Deduplicate parents before importing changesets
murugapl Aug 18, 2025
ec09952
Merge pull request #4308 from nhsuk/fix-parent-deduplication-imports
murugapl Aug 18, 2025
6633ac6
Avoid implicit ordering in test
thomasleese Aug 18, 2025
2389449
Add new vaccine icons
jhenderson Aug 18, 2025
a104e79
Merge pull request #4310 from nhsuk/add-vaccine-method-icons
jhenderson Aug 18, 2025
e63ed49
Revert "Add new vaccine icons"
jhenderson Aug 18, 2025
91a21b5
Merge pull request #4309 from nhsuk/patient-row-ordering
thomasleese Aug 18, 2025
a9316e0
Merge pull request #4312 from nhsuk/revert-add-vaccine-method-icons
jhenderson Aug 18, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 48 additions & 1 deletion .github/workflows/deploy-application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ on:
- all
- web
- good-job
- sidekiq
default: all
workflow_call:
inputs:
Expand Down Expand Up @@ -82,7 +83,9 @@ jobs:
"application_group=" + .codedeploy_deployment_group_name.value,
"cluster_name=" + .ecs_variables.value.cluster_name,
"good_job_service=" + .ecs_variables.value.good_job.service_name,
"good_job_task_definition=" + .ecs_variables.value.good_job.task_definition.arn
"good_job_task_definition=" + .ecs_variables.value.good_job.task_definition.arn,
"sidekiq_service=" + .ecs_variables.value.sidekiq.service_name,
"sidekiq_task_definition=" + .ecs_variables.value.sidekiq.task_definition.arn
' > ${{ runner.temp }}/DEPLOYMENT_ENVS
- name: Upload Artifact
uses: actions/upload-artifact@v4
Expand Down Expand Up @@ -166,3 +169,47 @@ jobs:
exit 1
fi
echo "Deployment successful"

create-sidekiq-deployment:
name: Create sidekiq deployment
runs-on: ubuntu-latest
needs: prepare-deployment
if: inputs.server_types == 'sidekiq' || inputs.server_types == 'all'
permissions:
id-token: write
steps:
- name: Download Artifact
uses: actions/download-artifact@v5
with:
name: DEPLOYMENT_ENVS-${{ inputs.environment }}
path: ${{ runner.temp }}
- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: ${{ env.aws-role }}
aws-region: eu-west-2
- name: Trigger ECS Deployment
run: |
set -e
source ${{ runner.temp }}/DEPLOYMENT_ENVS
DEPLOYMENT_ID=$(aws ecs update-service --cluster $cluster_name --service $sidekiq_service \
--task-definition $sidekiq_task_definition --force-new-deployment \
--query 'service.deployments[?rolloutState==`IN_PROGRESS`].[id][0]' --output text)
echo "Deployment started: $DEPLOYMENT_ID"
echo "deployment_id=$DEPLOYMENT_ID" >> $GITHUB_ENV
- name: Wait for deployment to complete
run: |
set -e
source ${{ runner.temp }}/DEPLOYMENT_ENVS
DEPLOYMENT_STATE=IN_PROGRESS
while [ "$DEPLOYMENT_STATE" == "IN_PROGRESS" ]; do
echo "Waiting for deployment to complete..."
sleep 30
DEPLOYMENT_STATE="$(aws ecs describe-services --cluster $cluster_name --services $sidekiq_service \
--query "services[0].deployments[?id == \`$deployment_id\`].[rolloutState][0]" --output text)"
done
if [ "$DEPLOYMENT_STATE" != "COMPLETED" ]; then
echo "Deployment failed with state: $DEPLOYMENT_STATE"
exit 1
fi
echo "Deployment successful"
1 change: 1 addition & 0 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ on:
- all
- web
- good-job
- sidekiq
- none
default: all

Expand Down
2 changes: 2 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ gem "ruby-progressbar"
gem "rubyzip"
gem "sentry-rails"
gem "sentry-ruby"
gem "sidekiq"
gem "sidekiq-throttled"
gem "splunk-sdk-ruby"
gem "table_tennis"
gem "tzinfo-data", platforms: %i[mingw mswin x64_mingw jruby]
Expand Down
23 changes: 19 additions & 4 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -521,6 +521,9 @@ GEM
erb
psych (>= 4.0.0)
redcarpet (3.6.1)
redis-client (0.25.2)
connection_pool
redis-prescription (2.6.0)
regexp_parser (2.11.2)
reline (0.6.2)
io-console (~> 0.5)
Expand Down Expand Up @@ -572,14 +575,14 @@ GEM
rubocop-capybara (2.22.1)
lint_roller (~> 1.1)
rubocop (~> 1.72, >= 1.72.1)
rubocop-govuk (5.1.19)
rubocop-govuk (5.1.20)
rubocop (= 1.79.2)
rubocop-ast (= 1.46.0)
rubocop-capybara (= 2.22.1)
rubocop-rails (= 2.32.0)
rubocop-rails (= 2.33.3)
rubocop-rake (= 0.7.1)
rubocop-rspec (= 3.6.0)
rubocop-rails (2.32.0)
rubocop-rails (2.33.3)
activesupport (>= 4.2.0)
lint_roller (~> 1.1)
rack (>= 1.1)
Expand Down Expand Up @@ -615,6 +618,16 @@ GEM
concurrent-ruby (~> 1.0, >= 1.0.2)
shoulda-matchers (6.5.0)
activesupport (>= 5.2.0)
sidekiq (8.0.7)
connection_pool (>= 2.5.0)
json (>= 2.9.0)
logger (>= 1.6.2)
rack (>= 3.1.0)
redis-client (>= 0.23.2)
sidekiq-throttled (2.0.0)
concurrent-ruby (>= 1.2.0)
redis-prescription (~> 2.2)
sidekiq (>= 8.0)
simplecov (0.22.0)
docile (~> 1.1)
simplecov-html (~> 0.11)
Expand Down Expand Up @@ -682,7 +695,7 @@ GEM
tzinfo (2.0.6)
concurrent-ruby (~> 1.0)
uk_postcode (2.1.8)
unicode-display_width (3.1.4)
unicode-display_width (3.1.5)
unicode-emoji (~> 4.0, >= 4.0.4)
unicode-emoji (4.0.4)
uri (1.0.3)
Expand Down Expand Up @@ -810,6 +823,8 @@ DEPENDENCIES
sentry-rails
sentry-ruby
shoulda-matchers
sidekiq
sidekiq-throttled
simplecov
solargraph
solargraph-rails
Expand Down
6 changes: 2 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -337,10 +337,8 @@ See the [releasing documentation](docs/releasing.md) for more information.

## Rake tasks

- `access_log:for_patient[id]`
- `access_log:for_user[id]`
- `subteams:create[ods_code,name,email,phone]`
- `users:create[email,password,given_name,family_name,team_ods_code]`
- `feature_flags:seed`
- `smoke:seed`
- `vaccines:seed[type]`

See the [Rake tasks documentation](docs/rake-tasks.md) for more information.
Expand Down
46 changes: 19 additions & 27 deletions app/components/app_patient_programmes_table_component.rb
Original file line number Diff line number Diff line change
Expand Up @@ -73,15 +73,7 @@ def build_rows(programme:, academic_year:, vaccination_records:)
end

def build_row_for_programme(programme:, academic_year:)
cached_vaccination_status =
@patient.vaccination_status(programme:, academic_year:)

vaccination_status = {
status: cached_vaccination_status.status.to_sym,
latest_session_status:
cached_vaccination_status.latest_session_status.to_sym,
status_changed_at: cached_vaccination_status.status_changed_at
}
vaccination_status = patient.vaccination_status(programme:, academic_year:)

[
name_for_programme(programme:, academic_year:),
Expand Down Expand Up @@ -115,14 +107,13 @@ def name_for_programme(programme:, academic_year:)
end

def status_for_programme(vaccination_status:, programme:, academic_year:)
status = vaccination_status[:status]
if status == :none_yet &&
if vaccination_status.none_yet? &&
eligibility_start_in_future?(programme:, academic_year:)
return "-"
end

label = I18n.t(status, scope: "status.programme.label")
colour = I18n.t(status, scope: "status.programme.colour")
label = I18n.t(vaccination_status.status, scope: "status.programme.label")
colour = I18n.t(vaccination_status.status, scope: "status.programme.colour")
tag.strong(label, class: "nhsuk-tag nhsuk-tag--#{colour}")
end

Expand All @@ -143,40 +134,42 @@ def calculate_earliest_academic_year(programme:, academic_year:)
end

def notes_for_programme(vaccination_status:, programme:, academic_year:)
case vaccination_status[:status]
when :vaccinated
if vaccination_status.vaccinated?
notes_for_status(vaccination_status:)
when :could_not_vaccinate
elsif vaccination_status.could_not_vaccinate?
could_not_vaccinate_notes(vaccination_status:)
when :none_yet
else
no_outcome_yet_notes(vaccination_status:, programme:, academic_year:)
end
end

def notes_for_status(vaccination_status:)
latest_session_status =
vaccination_status[:latest_session_status].to_s.humanize
date = vaccination_status[:status_changed_at].to_date.to_fs(:long)
vaccination_status.latest_session_status.to_s.humanize
date = vaccination_status.status_changed_at.to_date.to_fs(:long)
"#{latest_session_status} on #{date}"
end

def could_not_vaccinate_notes(vaccination_status:)
if vaccination_status[:latest_session_status] == :had_contraindications
if vaccination_status.latest_session_status_had_contraindications?
latest_triage =
@patient
.triages
.includes(:performed_by)
.find_by(created_at: vaccination_status[:status_changed_at])
.find_by(created_at: vaccination_status.status_changed_at)

nurse = latest_triage.performed_by
"#{nurse.full_name} decided that #{patient.full_name} could not be vaccinated"
if latest_triage
"#{latest_triage.performed_by.full_name} decided that #{patient.full_name} could not be vaccinated"
else
"#{patient.full_name} could not be vaccinated"
end
else
notes_for_status(vaccination_status:)
end
end

def no_outcome_yet_notes(vaccination_status:, programme:, academic_year:)
if vaccination_status[:latest_session_status] == :none_yet
if vaccination_status.latest_session_status_none_yet?
eligibility_notes(programme:, academic_year:)
else
notes_for_status(vaccination_status:)
Expand Down Expand Up @@ -231,9 +224,8 @@ def multi_dose?(vaccination_record:)
def status_for_administered_record(vaccination_record:)
if vaccination_record.administered?
status_for_programme(
vaccination_status: {
status: :vaccinated
},
vaccination_status:
Patient::VaccinationStatus.new(status: "vaccinated"),
programme: nil,
academic_year: nil
)
Expand Down
2 changes: 1 addition & 1 deletion app/jobs/commit_patient_changesets_job.rb
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ def perform(import)

def import_patients_and_parents(changesets, import)
patients = changesets.map(&:patient)
parents = changesets.flat_map(&:parents)
parents = changesets.flat_map(&:parents).uniq
relationships =
changesets
.flat_map(&:parent_relationships)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# frozen_string_literal: true

module NHSAPIConcurrencyConcern
module ImmunisationsAPIThrottlingConcern
extend ActiveSupport::Concern

include GoodJob::ActiveJobExtensions::Concurrency
Expand Down
16 changes: 16 additions & 0 deletions app/jobs/concerns/pds_api_throttling_concern.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# frozen_string_literal: true

module PDSAPIThrottlingConcern
extend ActiveSupport::Concern

include Sidekiq::Job
include Sidekiq::Throttled::Job

included do
self.queue_adapter = :sidekiq unless Rails.env.test?

sidekiq_throttle_as :pds

retry_on Faraday::ServerError, wait: :polynomially_longer
end
end
5 changes: 1 addition & 4 deletions app/jobs/consent_form_matching_job.rb
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
# frozen_string_literal: true

class ConsentFormMatchingJob < ApplicationJob
def self.concurrent_jobs_per_second = 5
def self.concurrency_key = :pds

include NHSAPIConcurrencyConcern
include PDSAPIThrottlingConcern

queue_as :consents

Expand Down
2 changes: 1 addition & 1 deletion app/jobs/enqueue_update_patients_from_pds_job.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,6 @@ def perform
.or(scope.where("updated_from_pds_at < ?", 12.hours.ago))
.order("updated_from_pds_at ASC NULLS FIRST")

UpdatePatientsFromPDS.call(patients, priority: 50, queue: :pds)
UpdatePatientsFromPDS.call(patients, queue: :pds)
end
end
7 changes: 2 additions & 5 deletions app/jobs/patient_nhs_number_lookup_job.rb
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
# frozen_string_literal: true

class PatientNHSNumberLookupJob < ApplicationJob
def self.concurrent_jobs_per_second = 5
def self.concurrency_key = :pds
include PDSAPIThrottlingConcern

include NHSAPIConcurrencyConcern

queue_as :imports
queue_as :pds

def perform(patient)
return if patient.nhs_number.present? && !patient.invalidated?
Expand Down
5 changes: 1 addition & 4 deletions app/jobs/patient_update_from_pds_job.rb
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
# frozen_string_literal: true

class PatientUpdateFromPDSJob < ApplicationJob
def self.concurrent_jobs_per_second = 5
def self.concurrency_key = :pds

include NHSAPIConcurrencyConcern
include PDSAPIThrottlingConcern

queue_as :pds

Expand Down
Loading