From 14c8fa63da1eebc94680e9caeec42f5de0436796 Mon Sep 17 00:00:00 2001 From: Samuel Young Date: Thu, 27 Nov 2025 17:49:50 +0000 Subject: [PATCH] CLDC-4066: Increase our resilience to an OS Places outage (#3104) * CLDC-4066: Implement a debounce on address search disappointingly the underlying library https://github.com/alphagov/accessible-autocomplete doesn't have this as an option, though we can implement one ourselves in the fetch code * CLDC-4066: Reduce read timeout for OS Places APIs 30 -> 15 in practice waiting up to 1 min 30 for requests could cause too many threads to be blocked under periods of slow OS Places API this reduces the max wait time to 45 seconds, as requested by CORE * CLDC-4066: Lint * CLDC-4066: Fix uprn timeout to match address search --- .../controllers/address_search_controller.js | 18 ++++++++++++++++++ app/services/address_client.rb | 2 +- app/services/uprn_client.rb | 2 +- 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/app/frontend/controllers/address_search_controller.js b/app/frontend/controllers/address_search_controller.js index de54090ec..b3410e49d 100644 --- a/app/frontend/controllers/address_search_controller.js +++ b/app/frontend/controllers/address_search_controller.js @@ -4,10 +4,28 @@ import 'accessible-autocomplete/dist/accessible-autocomplete.min.css' const options = [] +let latestQueryId = 0 + +const sleep = (ms) => { + return new Promise(resolve => setTimeout(resolve, ms)) +} + const fetchOptions = async (query, searchUrl) => { if (query.length < 2) { throw new Error('Query must be at least 2 characters long.') } + + // implement a debounce + // this is because this API has periods of high latency if OS Places has an outage + // making too many requests can overwhelm the number of threads available on the server + // which can in turn cause a site wide outage + latestQueryId++ + const myQueryId = latestQueryId + await sleep(500) + if (myQueryId !== latestQueryId) { + throw new Error('Outdated query, ignoring result.') + } + try { const response = await fetch(`${searchUrl}?query=${encodeURIComponent(query.trim())}`) return await response.json() diff --git a/app/services/address_client.rb b/app/services/address_client.rb index 20cf603fe..3fca0a0d0 100644 --- a/app/services/address_client.rb +++ b/app/services/address_client.rb @@ -35,7 +35,7 @@ private client.use_ssl = true client.verify_mode = OpenSSL::SSL::VERIFY_PEER client.max_retries = 3 - client.read_timeout = 30 # seconds + client.read_timeout = 15 # seconds client end diff --git a/app/services/uprn_client.rb b/app/services/uprn_client.rb index f847c7da5..8dcd2e7a0 100644 --- a/app/services/uprn_client.rb +++ b/app/services/uprn_client.rb @@ -39,7 +39,7 @@ private client.use_ssl = true client.verify_mode = OpenSSL::SSL::VERIFY_PEER client.max_retries = 3 - client.read_timeout = 30 # seconds + client.read_timeout = 15 # seconds client end