Improve consistency of caching and data storage #118

Closed
opened 2026-07-26 20:09:29 +00:00 by ian · 5 comments
Owner

Provide a common wrapper for both hot (spots, alerts) and cold (semi-static and other lookups) data caches.

Hot data should use TTLCache and a separate thread to page to disk every X minutes and on shutdown, rather than writing to disk on every change like diskcache currently does.

Solar conditions is more like a cold data store as it doesn't expire... But maybe the forecast bits should do rather than being managed with a separate cleanup thread. This makes the solar conditions data store a bit of a complex special case.

Replace the way storing in-memory dicts of data currently works, rather than request caching on every use we should have a separate thread that handles querying the semi-static URLs and storing in the cold data store every e.g. 30 days and on startup if the data is old/missing. There's no need to expire this data, just to try and replace it on a cron job-like basis.

Clublog / cty.dat stuff should move to the same way of working with the cold data cache with no expiry and a thread that fetches the data from source every so often. Might need to move away from pyhamtools to allow this.

With QRZ etc lookups we should do something similar, replace our in-memory dicts with the cold data store, use the data from cache until it expires, but then re-query the server the next time it's needed after that - we don't want a thread getting QRZ data with random credentials, they have to come from the user making the request.

There should be no need for requests cache library, we should be controlling whether a request happens at all based on our own data store validity rather than just making web requests and letting requests cache handle whether it happens or not.

But for that to happen we do need a way of saying "QRZ had no data, stop asking", maybe by storing an empty map of data for the callsign in a callaign-data structure.

Maybe if we are caching WWFF etc data in a nicer way, we should actually do the same for POTA etc as well instead of a live lookup. I think there are downloadable data files for all programmes? Set up a whole set of new providers similar to spotproviders etc to power this, report status etc.

Provide a common wrapper for both hot (spots, alerts) and cold (semi-static and other lookups) data caches. Hot data should use TTLCache and a separate thread to page to disk every X minutes and on shutdown, rather than writing to disk on every change like diskcache currently does. Solar conditions is more like a cold data store as it doesn't expire... But maybe the forecast bits should do rather than being managed with a separate cleanup thread. This makes the solar conditions data store a bit of a complex special case. Replace the way storing in-memory dicts of data currently works, rather than request caching on every use we should have a separate thread that handles querying the semi-static URLs and storing in the cold data store every e.g. 30 days and on startup if the data is old/missing. There's no need to expire this data, just to try and replace it on a cron job-like basis. Clublog / cty.dat stuff should move to the same way of working with the cold data cache with no expiry and a thread that fetches the data from source every so often. Might need to move away from pyhamtools to allow this. With QRZ etc lookups we should do something similar, replace our in-memory dicts with the cold data store, use the data from cache until it expires, but then re-query the server the next time it's needed after that - we don't want a thread getting QRZ data with random credentials, they have to come from the user making the request. There should be no need for requests cache library, we should be controlling whether a request happens at all based on our own data store validity rather than just making web requests and letting requests cache handle whether it happens or not. But for that to happen we do need a way of saying "QRZ had no data, stop asking", maybe by storing an empty map of data for the callsign in a callaign-data structure. Maybe if we are caching WWFF etc data in a nicer way, we should actually do the same for POTA etc as well instead of a live lookup. I think there are downloadable data files for all programmes? Set up a whole set of new providers similar to spotproviders etc to power this, report status etc.
ian added this to the 2.0 milestone 2026-07-26 20:09:29 +00:00
ian self-assigned this 2026-07-26 20:09:29 +00:00
ian changed title from Redis backend to Improve consistency of caching and data storage 2026-07-27 07:07:36 +00:00
ian modified the milestone from 2.0 to 1.4 2026-07-27 08:07:39 +00:00
Author
Owner

Finished SIG lookups. Now got a weird problem where infer_missing is super slow. Also app doesn't shut down properly, need to try and stop it then py-spy threads to see what's still running.

Callsign lookup, Clublog/CTY are still to do, as is improving the URL data cache mechanism.

Finished SIG lookups. Now got a weird problem where infer_missing is super slow. Also app doesn't shut down properly, need to try and stop it then py-spy threads to see what's still running. Callsign lookup, Clublog/CTY are still to do, as is improving the URL data cache mechanism.
Author
Owner

Performance problem is resolved I think.

Performance problem is resolved I think.
ian referenced this issue from a commit 2026-08-01 07:06:49 +00:00
ian referenced this issue from a commit 2026-08-01 08:32:20 +00:00
Author
Owner

Callsign lookup, Clublog/CTY still to do.

I think we also need to change our caching approach so that everything is an in-memory cache with timed snapshot storing to diskcache. Currently we are hitting performance penalties with stuff like dxcc_data where we have to iterate through all dxccs finding a matching callsign regex, which is being slowed down because every entry needs unpickling every time.

Callsign lookup, Clublog/CTY still to do. I think we also need to change our caching approach so that _everything_ is an in-memory cache with timed snapshot storing to diskcache. Currently we are hitting performance penalties with stuff like dxcc_data where we have to iterate through all dxccs finding a matching callsign regex, which is being slowed down because every entry needs unpickling every time.
Author
Owner

OK, callsign regex stuff sorted.

Next up Clublog/CTY if we can.

For callsign lookup, I think it's flawed to generate a single callsign-lookup-data object for a single callsign, because for example if the user didn't provide QRZ credentials, that will be generated without QRZ data. If the user later provides credentials but the old data object TTL hasn't expired, how do we know we can now re-fetch better data? Maybe we do need to keep the current structure where QRZ and HamQTH data are cached separately and merged if available on request. But these can still be our own (newly defined) objects rather than caching the server response.

OK, callsign regex stuff sorted. Next up Clublog/CTY if we can. For callsign lookup, I think it's flawed to generate a single callsign-lookup-data object for a single callsign, because for example if the user didn't provide QRZ credentials, that will be generated without QRZ data. If the user later provides credentials but the old data object TTL hasn't expired, how do we know we can now re-fetch better data? Maybe we do need to keep the current structure where QRZ and HamQTH data are cached separately and merged if available on request. But these can still be our own (newly defined) objects rather than caching the server response.
Author
Owner

Callsign lookup:

  • Create new providers structure
  • See if we can load cty/clublog files into lookuplib direct from web as a stream, if not then create files and load files as current
  • cty/clublog file provides should reload every 30 days
  • Create QRZ/HamQTH/Clublog API providers
  • Each provider creates a CallInfo not just a lookuplib
  • Each provider has a lookup(call, credentials) method, returns a new Callsign data object
  • Each provider has their own cache of Callsign objects in DataStore, TTL 30 days, returns that if present instead of querying API or looking up from file. Implement this at the top level abstract class, passing in a reference to the right DataStore cache. The abstract class should have the method that gets called from outside and runs the "is it in cache" code; the implementations shouldn't override this anymore but instead override a new "inner" perform_new_lookup method
  • Avoid caching QRZ/HamQTH data if no credentials supplied
  • Lookup helper should be much simpler, accesses all relevant callsign lookup providers, iterates through and merges results
  • Replace all usages of the old lookup helper methods
  • Somehow handle needing a deterministic order in callsign lookups where QRZ location supersedes Clublog location etc. Priority flags in config?
  • Fix not adding any data into the spot for country etc.
  • Remove "fake spot" business in lookups.py
  • Tweak API if necessary, should hopefully be the same but make sure our Callsign info object in the API doc is structured the same as our new object in code
  • Count lookups made for each provider and put on status page?
  • Common approach between callsign_lookup_helper and sig_lookup_helper
  • Fix QRZ/HamQTH not returning anything or not being called even when the UI has credentials loaded
  • Fix whatever has happened to the SSE mechanism, doesn't seem that reliable any more
  • Frontend should hide QRZ/HamQTH if backend does not have them enabled; remove Your Data button completely if neither available.
  • Still not shutting down nicely even after being given lots of time to start everything. py-spy thread dump after requesting shutdown and see what's running.
  • I think we are probably counting HamQTH lookups as towards out lookup count if they don't return any real data
Callsign lookup: - [x] Create new providers structure - [x] See if we can load cty/clublog files into lookuplib direct from web as a stream, if not then create files and load files as current - [x] cty/clublog file provides should reload every 30 days - [x] Create QRZ/HamQTH/Clublog API providers - [x] Each provider creates a CallInfo not just a lookuplib - [x] Each provider has a lookup(call, credentials) method, returns a new Callsign data object - [x] Each provider has their own cache of Callsign objects in DataStore, TTL 30 days, returns that if present instead of querying API or looking up from file. Implement this at the top level abstract class, passing in a reference to the right DataStore cache. The abstract class should have the method that gets called from outside and runs the "is it in cache" code; the implementations shouldn't override this anymore but instead override a new "inner" perform_new_lookup method - [x] Avoid caching QRZ/HamQTH data if no credentials supplied - [x] Lookup helper should be much simpler, accesses all relevant callsign lookup providers, iterates through and merges results - [x] Replace all usages of the old lookup helper methods - [x] Somehow handle needing a deterministic order in callsign lookups where QRZ location supersedes Clublog location etc. Priority flags in config? - [x] Fix not adding any data into the spot for country etc. - [x] Remove "fake spot" business in lookups.py - [x] Tweak API if necessary, should hopefully be the same but make sure our Callsign info object in the API doc is structured the same as our new object in code - [x] Count lookups made for each provider and put on status page? - [x] Common approach between callsign_lookup_helper and sig_lookup_helper - [x] Fix QRZ/HamQTH not returning anything or not being called even when the UI has credentials loaded - [x] Fix whatever has happened to the SSE mechanism, doesn't seem that reliable any more - [x] Frontend should hide QRZ/HamQTH if backend does not have them enabled; remove Your Data button completely if neither available. - [x] Still not shutting down nicely even after being given lots of time to start everything. py-spy thread dump after requesting shutdown and see what's running. - [x] I think we are probably counting HamQTH lookups as towards out lookup count if they don't return any real data
ian modified the milestone from 1.4 to 2.0 2026-08-02 10:39:37 +00:00
ian closed this issue 2026-08-04 20:59:29 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
ian/spothole#118
No description provided.