11
11
import io .javaoperatorsdk .operator .processing .event .ResourceID ;
12
12
import io .javaoperatorsdk .operator .processing .event .source .CachingEventSource ;
13
13
14
+ /**
15
+ * <p>
16
+ * Pols resource (on contrary to {@link PerResourcePollingEventSource}) not per resource bases but
17
+ * instead to calls supplier periodically and independently of the number of state of custom
18
+ * resources managed by the operator. It is called on start (synced). This means that when the
19
+ * reconciler first time executed on startup a poll already happened before. So if the cache does
20
+ * not contain the target resource it means it is not created yet or was deleted while an operator
21
+ * was not running.
22
+ * </p>
23
+ * <p>
24
+ * Another caveat with this is if the cached object is checked in the reconciler and created since
25
+ * not in the cache it should be manually added to the cache, since it can happen that the
26
+ * reconciler is triggered before the cache is propagated with the new resource from a scheduled
27
+ * execution. See {@link PollingEventSource##put(ResourceID, Object)}.
28
+ * </p>
29
+ * So the generic workflow in reconciler should be:
30
+ *
31
+ * <ul>
32
+ * <li>Check if the cache contains the resource.</li>
33
+ * <li>If cache contains the resource reconcile it - compare with target state, update if necessary
34
+ * </li>
35
+ * <li>if cache not contains the resource create it.</li>
36
+ * <li>If the resource was created or updated, put the new version of the resource manually to the
37
+ * cache.</li>
38
+ * </ul>
39
+ *
40
+ * @param <T> type of the polled resource
41
+ * @param <P> primary resource type
42
+ */
14
43
public class PollingEventSource <T , P extends HasMetadata > extends CachingEventSource <T , P > {
15
44
16
45
private static final Logger log = LoggerFactory .getLogger (PollingEventSource .class );
@@ -29,6 +58,7 @@ public PollingEventSource(Supplier<Map<ResourceID, T>> supplier,
29
58
@ Override
30
59
public void start () throws OperatorException {
31
60
super .start ();
61
+ getStateAndFillCache ();
32
62
timer .schedule (new TimerTask () {
33
63
@ Override
34
64
public void run () {
@@ -47,6 +77,10 @@ protected void getStateAndFillCache() {
47
77
cache .keys ().filter (e -> !values .containsKey (e )).forEach (super ::handleDelete );
48
78
}
49
79
80
+ public void put (ResourceID key , T resource ) {
81
+ cache .put (key , resource );
82
+ }
83
+
50
84
@ Override
51
85
public void stop () throws OperatorException {
52
86
super .stop ();
@@ -61,15 +95,7 @@ public void stop() throws OperatorException {
61
95
*/
62
96
@ Override
63
97
public Optional <T > getAssociated (P primary ) {
64
- return getValueFromCacheOrSupplier (ResourceID .fromResource (primary ));
98
+ return getCachedValue (ResourceID .fromResource (primary ));
65
99
}
66
100
67
- public Optional <T > getValueFromCacheOrSupplier (ResourceID resourceID ) {
68
- var resource = getCachedValue (resourceID );
69
- if (resource .isPresent ()) {
70
- return resource ;
71
- }
72
- getStateAndFillCache ();
73
- return getCachedValue (resourceID );
74
- }
75
101
}
0 commit comments