Class HomeStatsRefresher
HomeStats on a daily cron AND on every Spring context refresh
(startup). The two triggers use different Spring mechanisms on purpose:
Startup pass rides on ContextRefreshedEvent so it fires in every
server context — REST, dev, scheduler — regardless of whether
@EnableScheduling is active (it is skipped under the
EnvironmentProfiles.CLI profile, which has no
homepage to warm). @Scheduled now fires on production nodes too (see
AnnotationDrivenSchedulingConfig), but not under dev or test, so the
lifecycle event remains the only trigger there.
It runs the refresh in a background thread so Spring startup isn't blocked by the
minute-or-two cold-cache aggregation pass.
Daily cron stays on Scheduled. It only fires on nodes with the
scheduler profile active (which is what we want — daily refresh is a single-node
responsibility on the production scheduler). The cron default is 4 AM, after the
3 AM Lucene reindex in ScheduledSearchReindexer so the two heavy nightly
passes don't race for the connection pool.
Multi-container concurrency is benign: HomeStatsService.refresh() writes
to disk atomically (temp file + ATOMIC_MOVE) and the recompute itself is read-only,
so two nodes racing the same tick at worst do the work twice.
-
Constructor Summary
Constructors -
Method Summary
Modifier and TypeMethodDescriptionvoidDaily refresh.voidRecompute the snapshot on context startup.
-
Constructor Details
-
HomeStatsRefresher
public HomeStatsRefresher()
-
-
Method Details
-
refreshOnStartup
@EventListener(org.springframework.context.event.ContextRefreshedEvent.class) public void refreshOnStartup()Recompute the snapshot on context startup. Always runs (no skip-if-cached) so a fresh redeploy picks up new aggregation shape immediately — the on-disk snapshot loaded byHomeStatsServiceImpl.afterPropertiesSet()is whatGET /stats/homeserves until this background refresh completes; the stale-from-previous-build data stays available rather than 503-ing, but it's replaced as soon as the new compute finishes.Runs in a background thread so the cold-cache aggregation pass (~15-25s on a fresh DB cache) doesn't block Spring startup.
-
refreshDaily
@Scheduled(cron="${gemma.homeStats.refresh.cron:0 0 4 * * *}") public void refreshDaily()Daily refresh. Default cron: 4 AM, afterScheduledSearchReindexer. Only fires on nodes with@EnableSchedulingactive (the production scheduler profile); local-dev containers rely on the startup pass above.
-