11import logging
2+ import threading
23import time
34
45from django .db import connection
@@ -87,39 +88,43 @@ def __init__(self):
8788 # the cache has the lang as key, and I18nCacheEntry as a value:
8889 self .lang_cache = {}
8990 self ._last_check = 0
91+ self ._lock = threading .Lock ()
9092
9193 def get_entry (self , lang , data_key ):
9294 """
9395 returns date:str, data
9496 date is needed for checking the entry freshness when setting info
9597 data may be None if not cached or expired
9698 """
97- cached_entry : I18nCacheEntry = self .lang_cache .get (lang , None )
98-
99- time_now = time .time ()
100- needs_check = time_now - self ._last_check > I18nCache .CHECK_INTERVAL
101-
102- # if not needs_check:
103- # logger.debug(f"No cache check needed {lang}:{data_key} @ {cached_entry}")
104- # else:
105- # logger.debug(f"Cache check needed {lang}:{data_key} @ {cached_entry}")
106-
107- if needs_check or not cached_entry :
108- self ._last_check = time_now
109- thesaurus_date = ( # may be none if thesaurus does not exist
110- Thesaurus .objects .filter (identifier = I18N_THESAURUS_IDENTIFIER ).values_list ("date" , flat = True ).first ()
111- )
112- if cached_entry and cached_entry .date != thesaurus_date :
113- logger .info (f"Cache for { lang } :{ data_key } needs to be recreated" )
114- return thesaurus_date , None
115- if not cached_entry :
116- logger .info (f"Cache for { lang } :{ data_key } needs to be created" )
117- return thesaurus_date , None
118-
119- # logger.debug(f"Returning cached entry for {lang}:{data_key} @ {cached_entry.date}")
120- return cached_entry .date , cached_entry .caches .get (data_key , None )
121-
122- def set (self , lang : str , data_key : str , data : dict , request_date : str ):
99+ with self ._lock :
100+ cached_entry : I18nCacheEntry = self .lang_cache .get (lang , None )
101+
102+ time_now = time .time ()
103+ needs_check = time_now - self ._last_check > I18nCache .CHECK_INTERVAL
104+
105+ # if not needs_check:
106+ # logger.debug(f"No cache check needed {lang}:{data_key} @ {cached_entry}")
107+ # else:
108+ # logger.debug(f"Cache check needed {lang}:{data_key} @ {cached_entry}")
109+
110+ if needs_check or not cached_entry :
111+ self ._last_check = time_now
112+ thesaurus_date = ( # may be none if thesaurus does not exist
113+ Thesaurus .objects .filter (identifier = I18N_THESAURUS_IDENTIFIER )
114+ .values_list ("date" , flat = True )
115+ .first ()
116+ )
117+ if cached_entry and cached_entry .date != thesaurus_date :
118+ logger .info (f"Cache for { lang } :{ data_key } needs to be recreated" )
119+ return thesaurus_date , None
120+ if not cached_entry :
121+ logger .info (f"Cache for { lang } :{ data_key } needs to be created" )
122+ return thesaurus_date , None
123+
124+ # logger.debug(f"Returning cached entry for {lang}:{data_key} @ {cached_entry.date}")
125+ return cached_entry .date , cached_entry .caches .get (data_key , None )
126+
127+ def set (self , lang : str , data_key : str , data , request_date : str ):
123128 # TODO: check if lang is allowed
124129 cached_entry : I18nCacheEntry = self .lang_cache .setdefault (lang , I18nCacheEntry ())
125130
@@ -132,15 +137,21 @@ def set(self, lang: str, data_key: str, data: dict, request_date: str):
132137 logger .debug (f"Caching lang:{ lang } key:{ data_key } date:{ request_date } " )
133138 cached_entry .date = latest_date
134139 cached_entry .caches [data_key ] = data
140+ return True
135141 else :
136142 logger .warning (
137143 f"Cache will not be updated for lang:{ lang } key:{ data_key } reqdate:{ request_date } latest:{ latest_date } "
138144 )
145+ return False
139146
140147 def clear (self ):
141148 logger .info ("Clearing i18n cache" )
142149 self .lang_cache .clear ()
143150
151+ def force_check (self ):
152+ """For testing: forces a check against the DB on the next get_entry call."""
153+ self ._last_check = 0
154+
144155
145156class LabelResolver :
146157 CACHE_KEY_LABELS = "labels"
0 commit comments