-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathContentRefreshScheduler.java
More file actions
73 lines (67 loc) · 3 KB
/
Copy pathContentRefreshScheduler.java
File metadata and controls
73 lines (67 loc) · 3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
package com.openelements.content;
import com.openelements.spring.base.services.search.SearchReadinessState;
import java.util.concurrent.atomic.AtomicBoolean;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
/**
* Periodically re-runs incremental ingestion over all enabled sources, reusing {@link ContentIndexer}
* so scheduled refresh and startup bootstrap (spec 009) share identical semantics.
*
* <p>Driven by the configurable {@code open-elements.content.refresh-cron} (default hourly). A tick is
* a no-op while the content pipeline is disabled or Meilisearch is still bootstrapping, and runs never
* overlap — if a refresh is still in progress when the next tick fires, that tick is skipped. A source
* that fails to index is logged and does not stop the others.
*
* <p>Only created when the Meilisearch stack is enabled (it depends on {@link ContentIndexer}).
*/
@Component
@ConditionalOnProperty(prefix = "openelements.meilisearch", name = "enabled", havingValue = "true")
public class ContentRefreshScheduler {
private static final Logger log = LoggerFactory.getLogger(ContentRefreshScheduler.class);
private final ContentSourceProperties properties;
private final ContentIndexer indexer;
private final SearchReadinessState readinessState;
private final AtomicBoolean running = new AtomicBoolean(false);
public ContentRefreshScheduler(ContentSourceProperties properties, ContentIndexer indexer,
SearchReadinessState readinessState) {
this.properties = properties;
this.indexer = indexer;
this.readinessState = readinessState;
}
/**
* Refreshes every enabled source once. Bound to the {@code refresh-cron} property (default hourly).
*/
@Scheduled(cron = "${open-elements.content.refresh-cron:0 0 * * * *}")
public void refresh() {
if (!properties.enabled()) {
log.debug("Content pipeline disabled; skipping refresh");
return;
}
if (readinessState.isBootstrapping()) {
log.debug("Bootstrap in progress; skipping refresh");
return;
}
if (!running.compareAndSet(false, true)) {
log.info("Previous refresh still running; skipping this tick");
return;
}
try {
for (ContentSource source : properties.sources()) {
if (!source.enabled()) {
continue;
}
try {
IndexReport report = indexer.indexSource(source);
log.info("Refreshed source {}: {}", source.id(), report);
} catch (Exception e) {
log.warn("Refresh failed for source {}: {}", source.id(), e.toString());
}
}
} finally {
running.set(false);
}
}
}