1010import io .getunleash .event .ClientFeaturesResponse ;
1111import io .getunleash .event .EventDispatcher ;
1212import io .getunleash .event .UnleashReady ;
13+ import io .getunleash .streaming .NoOpStreamingFeatureFetcher ;
14+ import io .getunleash .streaming .StreamingFeatureFetcher ;
15+ import io .getunleash .streaming .StreamingFeatureFetcherImpl ;
1316import io .getunleash .util .Throttler ;
1417import io .getunleash .util .UnleashConfig ;
1518import io .getunleash .util .UnleashScheduledExecutor ;
@@ -25,6 +28,7 @@ public class FeatureRepositoryImpl implements FeatureRepository {
2528 private final BackupHandler featureBackupHandler ;
2629 private final ToggleBootstrapProvider bootstrapper ;
2730 private final FeatureFetcher featureFetcher ;
31+ private final StreamingFeatureFetcher streamingFeatureFetcher ;
2832 private final EventDispatcher eventDispatcher ;
2933 private final UnleashEngine engine ;
3034 private final Throttler throttler ;
@@ -36,23 +40,43 @@ public FeatureRepositoryImpl(UnleashConfig unleashConfig, UnleashEngine engine)
3640
3741 public FeatureRepositoryImpl (
3842 UnleashConfig unleashConfig , BackupHandler featureBackupHandler , UnleashEngine engine ) {
39- this (
40- unleashConfig ,
41- featureBackupHandler ,
42- engine ,
43- unleashConfig .getUnleashFeatureFetcherFactory ().apply (unleashConfig ));
43+ this (unleashConfig , featureBackupHandler , engine , new EventDispatcher (unleashConfig ));
44+ }
45+
46+ private FeatureRepositoryImpl (
47+ UnleashConfig unleashConfig ,
48+ BackupHandler featureBackupHandler ,
49+ UnleashEngine engine ,
50+ EventDispatcher eventDispatcher ) {
51+ this .unleashConfig = unleashConfig ;
52+ this .featureBackupHandler = featureBackupHandler ;
53+ this .engine = engine ;
54+ this .featureFetcher = unleashConfig .getUnleashFeatureFetcherFactory ().apply (unleashConfig );
55+ this .bootstrapper = unleashConfig .getToggleBootstrapProvider ();
56+ this .eventDispatcher = eventDispatcher ;
57+ this .throttler = initializeThrottler (unleashConfig );
58+ this .streamingFeatureFetcher =
59+ unleashConfig .isStreamingMode ()
60+ ? new StreamingFeatureFetcherImpl (
61+ unleashConfig ,
62+ this ::handleStreamingUpdate ,
63+ this ::handleStreamingError )
64+ : new NoOpStreamingFeatureFetcher ();
65+ this .initCollections (unleashConfig .getScheduledExecutor ());
4466 }
4567
4668 public FeatureRepositoryImpl (
4769 UnleashConfig unleashConfig ,
4870 BackupHandler featureBackupHandler ,
4971 UnleashEngine engine ,
50- FeatureFetcher fetcher ) {
72+ FeatureFetcher fetcher ,
73+ StreamingFeatureFetcher streamingFeatureFetcher ) {
5174 this (
5275 unleashConfig ,
5376 featureBackupHandler ,
5477 engine ,
5578 fetcher ,
79+ streamingFeatureFetcher ,
5680 unleashConfig .getToggleBootstrapProvider ());
5781 }
5882
@@ -61,12 +85,14 @@ public FeatureRepositoryImpl(
6185 BackupHandler featureBackupHandler ,
6286 UnleashEngine engine ,
6387 FeatureFetcher fetcher ,
88+ StreamingFeatureFetcher streamingFeatureFetcher ,
6489 ToggleBootstrapProvider bootstrapHandler ) {
6590 this (
6691 unleashConfig ,
6792 featureBackupHandler ,
6893 engine ,
6994 fetcher ,
95+ streamingFeatureFetcher ,
7096 bootstrapHandler ,
7197 new EventDispatcher (unleashConfig ));
7298 }
@@ -76,22 +102,27 @@ public FeatureRepositoryImpl(
76102 BackupHandler featureBackupHandler ,
77103 UnleashEngine engine ,
78104 FeatureFetcher fetcher ,
105+ StreamingFeatureFetcher streamingFeatureFetcher ,
79106 ToggleBootstrapProvider bootstrapHandler ,
80107 EventDispatcher eventDispatcher ) {
81108 this .unleashConfig = unleashConfig ;
82109 this .featureBackupHandler = featureBackupHandler ;
83110 this .engine = engine ;
84111 this .featureFetcher = fetcher ;
112+ this .streamingFeatureFetcher = streamingFeatureFetcher ;
85113 this .bootstrapper = bootstrapHandler ;
86114 this .eventDispatcher = eventDispatcher ;
87- this .throttler =
88- new Throttler (
89- (int ) unleashConfig .getFetchTogglesInterval (),
90- 300 ,
91- unleashConfig .getUnleashURLs ().getFetchTogglesURL ());
115+ this .throttler = initializeThrottler (unleashConfig );
92116 this .initCollections (unleashConfig .getScheduledExecutor ());
93117 }
94118
119+ private Throttler initializeThrottler (UnleashConfig config ) {
120+ return new Throttler (
121+ (int ) config .getFetchTogglesInterval (),
122+ 300 ,
123+ config .getUnleashURLs ().getFetchTogglesURL ());
124+ }
125+
95126 @ SuppressWarnings ("FutureReturnValueIgnored" )
96127 private void initCollections (UnleashScheduledExecutor executor ) {
97128 Optional <String > features = this .featureBackupHandler .read ();
@@ -119,14 +150,18 @@ private void initCollections(UnleashScheduledExecutor executor) {
119150 }
120151 }
121152
122- if (!unleashConfig .isDisablePolling ()) {
153+ if (!unleashConfig .isDisablePolling () && ! unleashConfig . isStreamingMode () ) {
123154 Runnable updateFeatures = updateFeatures (this .eventDispatcher ::dispatch );
124155 if (unleashConfig .getFetchTogglesInterval () > 0 ) {
125156 executor .setInterval (updateFeatures , 0 , unleashConfig .getFetchTogglesInterval ());
126157 } else {
127158 executor .scheduleOnce (updateFeatures );
128159 }
129160 }
161+
162+ if (unleashConfig .isStreamingMode ()) {
163+ streamingFeatureFetcher .start ();
164+ }
130165 }
131166
132167 private Runnable updateFeatures (final Consumer <UnleashException > handler ) {
@@ -201,4 +236,35 @@ public WasmResponse<VariantDef> getVariant(String toggleName, UnleashContext con
201236 public Stream <FeatureDefinition > listKnownToggles () {
202237 return this .engine .listKnownToggles ().stream ().map (FeatureDefinition ::new );
203238 }
239+
240+ private synchronized void handleStreamingUpdate (String data ) {
241+ try {
242+ engine .takeState (data );
243+ // TODO: write backup when engine exposes current state
244+
245+ ClientFeaturesResponse response = ClientFeaturesResponse .updated (data );
246+ eventDispatcher .dispatch (response );
247+
248+ if (!ready ) {
249+ eventDispatcher .dispatch (new UnleashReady ());
250+ ready = true ;
251+ }
252+ } catch (Exception e ) {
253+ LOGGER .error ("Failed to process streaming update" , e );
254+ UnleashException unleashException =
255+ new UnleashException ("Failed to process streaming update" , e );
256+ eventDispatcher .dispatch (unleashException );
257+ }
258+ }
259+
260+ private void handleStreamingError (Throwable error ) {
261+ UnleashException unleashException =
262+ new UnleashException ("Streaming connection error" , error );
263+ eventDispatcher .dispatch (unleashException );
264+ }
265+
266+ @ Override
267+ public void shutdown () {
268+ this .streamingFeatureFetcher .stop ();
269+ }
204270}
0 commit comments