diff --git a/README.md b/README.md index 929bb9c..b33929a 100644 --- a/README.md +++ b/README.md @@ -101,16 +101,18 @@ nginx (https://schedule.our-place.ru) → 127.0.0.1:8090 ошибка, число групп); - **вставить новую ссылку**: она проверяется скачиванием и разбором таблицы до сохранения — нерабочая не применится, данные на сайте не пострадают; -- **принудительно обновить расписание** — вне интервала, не дожидаясь - фонового обновления (интервал и так перечитывает таблицу целиком); +- **принудительно обновить расписание** — вне интервала: кнопка перечитывает + таблицу всегда, не глядя на дату изменения файла; - **задать интервал обновления** в минутах (`1…1440`). -Каждое обновление (и по кнопке, и по интервалу) **всегда перечитывает таблицу**, -а в панели и в логе видно, изменился ли файл на Диске: `sha256`, время -последнего изменения содержимого и отметка «изменился / без изменений». -Если вы поправили таблицу, а после обновления написано «без изменений» — значит -публичная ссылка Яндекса отдаёт прежнюю версию файла (бывает с задержкой), -стоит повторить обновление через минуту. +Фоновое обновление по интервалу работает как раньше: сначала сверяется +`modified` файла, и если таблица не менялась — скачивания не происходит. +Принудительное обновление (кнопка) скачивает файл **всегда**, поэтому его и +стоит нажимать сразу после правок в таблице. В панели и в логе при этом видно, +изменилось ли содержимое файла: `sha256`, время последнего изменения и отметка +«изменился / без изменений». Если вы поправили таблицу, а после обновления +написано «без изменений» — значит публичная ссылка Яндекса отдаёт прежнюю +версию файла (бывает с задержкой), стоит повторить обновление через минуту. Как это устроено: diff --git a/src/backend/schedule/cache.py b/src/backend/schedule/cache.py index 6c8c801..aa76469 100644 --- a/src/backend/schedule/cache.py +++ b/src/backend/schedule/cache.py @@ -2,9 +2,9 @@ - однопоточная перезагрузка (lock): параллельные запросы во время загрузки ждут один download вместо N скачиваний; -- интервал обновления: по его истечении таблица перечитывается целиком - (поле modified у публичной ссылки может «застыть», поэтому на него не - опираемся — оно только показывается в админке); +- интервал обновления: по его истечении сверяем modified таблицы — если файл + не менялся, скачивание не повторяется; принудительное обновление из админки + (force_reload) перечитывает таблицу всегда; - stale-while-error: если таблица перестала скачиваться, отдаём последнее удачное состояние и повторяем попытку не чаще, чем раз в retry_after секунд (вместо скачивания на каждый запрос); @@ -218,10 +218,19 @@ class ScheduleCache: if not self._link: self._fail(ScheduleError(NO_LINK_ERROR), now) return - # Обновление интервала всегда перечитывает таблицу: поле modified у - # публичной ссылки может «застыть» (кэш на стороне Диска), и тогда - # проверка «таблица не менялась» держала бы старые данные бесконечно. + # Обновление по интервалу: сначала сверяем modified — если файл не + # менялся, скачивание не повторяем. Принудительное обновление (кнопка + # в админке) идёт через force_reload и качает файл всегда. modified = fetch_table_modified(self._link) + if ( + self._data is not None + and modified is not None + and modified == self._modified + ): + # таблица не менялась — источник доступен, данные актуальны + self._loaded_at = now + self._error = None + return try: self._load(now, modified) except ScheduleError as exc: diff --git a/tests/test_api.py b/tests/test_api.py index dc81d68..ba6af99 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -170,16 +170,16 @@ def test_cache_no_repeated_download(client, cache): assert cache.calls["download"] == 1 -def test_interval_refresh_always_downloads(cache): - """По интервалу таблица перечитывается всегда. +def test_modified_unchanged_no_download(cache): + """По интервалу сверяем modified: если таблица не менялась — не скачиваем. - Поле modified у публичной ссылки может «застыть», поэтому на него не - опираемся: иначе стенд показывал бы старые данные бесконечно. + Принудительное обновление из админки при этом качает файл всегда + (см. test_force_refresh_ignores_ttl_and_modified). """ cache._ttl = 0 cache.get() cache.get() - assert cache.calls["download"] == 2 # оба обновления по интервалу скачали таблицу + assert cache.calls["download"] == 1 assert cache.calls["modified"] >= 2