55
66import java .net .InetSocketAddress ;
77import java .time .Duration ;
8- import java .util .Collection ;
98import java .util .Collections ;
10- import java .util .HashSet ;
119import java .util .List ;
1210import java .util .Map ;
1311import java .util .Objects ;
1412import java .util .Optional ;
1513import java .util .Properties ;
16- import java .util .Set ;
17- import java .util .concurrent .ExecutionException ;
1814import java .util .concurrent .ExecutorService ;
19- import java .util .concurrent .TimeUnit ;
20- import java .util .concurrent .TimeoutException ;
2115import java .util .function .Function ;
2216import java .util .stream .Collectors ;
2317
3125import org .apache .kafka .clients .CommonClientConfigs ;
3226import org .apache .kafka .clients .admin .Admin ;
3327import org .apache .kafka .clients .admin .AdminClientConfig ;
34- import org .apache .kafka .clients .admin .ListTopicsResult ;
3528import org .apache .kafka .common .config .SaslConfigs ;
3629import org .apache .kafka .common .config .SslConfigs ;
3730import org .apache .kafka .streams .KafkaClientSupplier ;
6053public class KafkaStreamsProducer {
6154
6255 private static final Logger LOGGER = Logger .getLogger (KafkaStreamsProducer .class .getName ());
63- private static volatile boolean shutdown = false ;
6456
6557 private final ExecutorService executorService ;
6658 private final StreamsConfig streamsConfig ;
6759 private final KafkaStreams kafkaStreams ;
68- private final KafkaStreamsTopologyManager kafkaStreamsTopologyManager ;
60+ private final KafkaStreamsTopologyManager topologyManager ;
6961 private final Admin kafkaAdminClient ;
70- private final Duration topicsTimeout ;
71- private final List <String > trimmedTopics ;
7262
7363 @ Inject
7464 public KafkaStreamsProducer (KafkaStreamsSupport kafkaStreamsSupport , KafkaStreamsRuntimeConfig runtimeConfig ,
@@ -77,17 +67,14 @@ public KafkaStreamsProducer(KafkaStreamsSupport kafkaStreamsSupport, KafkaStream
7767 @ Identifier ("default-kafka-broker" ) Instance <Map <String , Object >> defaultConfiguration ,
7868 Instance <StateListener > stateListener , Instance <StateRestoreListener > globalStateRestoreListener ,
7969 Instance <StreamsUncaughtExceptionHandler > uncaughtExceptionHandlerListener ) {
80- shutdown = false ;
8170 // No producer for Topology -> nothing to do
8271 if (topology .isUnsatisfied ()) {
8372 LOGGER .warn ("No Topology producer; Kafka Streams will not be started" );
8473 this .executorService = null ;
8574 this .streamsConfig = null ;
8675 this .kafkaStreams = null ;
87- this .kafkaStreamsTopologyManager = null ;
76+ this .topologyManager = null ;
8877 this .kafkaAdminClient = null ;
89- this .topicsTimeout = null ;
90- this .trimmedTopics = null ;
9178 return ;
9279 }
9380
@@ -108,32 +95,23 @@ public KafkaStreamsProducer(KafkaStreamsSupport kafkaStreamsSupport, KafkaStream
10895 this .kafkaAdminClient = Admin .create (getAdminClientConfig (kafkaStreamsProperties ));
10996
11097 this .executorService = executorService ;
111-
112- this .topicsTimeout = runtimeConfig .topicsTimeout ();
113- this .trimmedTopics = isTopicsCheckEnabled () ? runtimeConfig .getTrimmedTopics () : Collections .emptyList ();
11498 this .streamsConfig = new StreamsConfig (kafkaStreamsProperties );
11599 this .kafkaStreams = initializeKafkaStreams (streamsConfig , topology .get (),
116100 kafkaClientSupplier , stateListener , globalStateRestoreListener , uncaughtExceptionHandlerListener );
117- this .kafkaStreamsTopologyManager = new KafkaStreamsTopologyManager (kafkaAdminClient );
118- }
119-
120- private boolean isTopicsCheckEnabled () {
121- return topicsTimeout .compareTo (Duration .ZERO ) > 0 ;
101+ this .topologyManager = new KafkaStreamsTopologyManager (kafkaAdminClient , topology .get (), runtimeConfig );
122102 }
123103
124104 public void onStartup (@ Observes StartupEvent event , Event <KafkaStreams > kafkaStreamsEvent ) {
125105 if (kafkaStreams != null ) {
126106 kafkaStreamsEvent .fire (kafkaStreams );
127107 executorService .execute (() -> {
128- if (isTopicsCheckEnabled ()) {
129- try {
130- waitForTopicsToBeCreated (kafkaAdminClient , trimmedTopics , topicsTimeout );
131- } catch (InterruptedException e ) {
132- Thread .currentThread ().interrupt ();
133- return ;
134- }
108+ try {
109+ topologyManager .waitForTopicsToBeCreated ();
110+ } catch (InterruptedException e ) {
111+ Thread .currentThread ().interrupt ();
112+ return ;
135113 }
136- if (!shutdown ) {
114+ if (!topologyManager . isClosed () ) {
137115 LOGGER .debug ("Starting Kafka Streams pipeline" );
138116 kafkaStreams .start ();
139117 }
@@ -159,11 +137,13 @@ public StreamsConfig getStreamsConfig() {
159137 @ Singleton
160138 @ Unremovable
161139 public KafkaStreamsTopologyManager kafkaStreamsTopologyManager () {
162- return kafkaStreamsTopologyManager ;
140+ return topologyManager ;
163141 }
164142
165143 void onStop (@ Observes ShutdownEvent event ) {
166- shutdown = true ;
144+ if (topologyManager != null ) {
145+ topologyManager .close ();
146+ }
167147 if (kafkaStreams != null ) {
168148 LOGGER .debug ("Stopping Kafka Streams pipeline" );
169149 kafkaStreams .close ();
@@ -329,37 +309,6 @@ private static String toHostPort(InetSocketAddress inetSocketAddress) {
329309 return inetSocketAddress .getHostString () + ":" + inetSocketAddress .getPort ();
330310 }
331311
332- private static void waitForTopicsToBeCreated (Admin adminClient , Collection <String > topicsToAwait , Duration timeout )
333- throws InterruptedException {
334- Set <String > lastMissingTopics = null ;
335- while (!shutdown ) {
336- try {
337- ListTopicsResult topics = adminClient .listTopics ();
338- Set <String > existingTopics = topics .names ().get (timeout .toMillis (), TimeUnit .MILLISECONDS );
339-
340- if (existingTopics .containsAll (topicsToAwait )) {
341- LOGGER .debug ("All expected topics created: " + topicsToAwait );
342- return ;
343- } else {
344- Set <String > missingTopics = new HashSet <>(topicsToAwait );
345- missingTopics .removeAll (existingTopics );
346-
347- // Do not spam warnings - topics may take time to be created by an operator like Strimzi
348- if (missingTopics .equals (lastMissingTopics )) {
349- LOGGER .debug ("Waiting for topic(s) to be created: " + missingTopics );
350- } else {
351- LOGGER .warn ("Waiting for topic(s) to be created: " + missingTopics );
352- lastMissingTopics = missingTopics ;
353- }
354- }
355- } catch (ExecutionException | TimeoutException e ) {
356- LOGGER .error ("Failed to get topic names from broker" , e );
357- } finally {
358- Thread .sleep (1_000 );
359- }
360- }
361- }
362-
363312 private static Properties getAdminClientConfig (Properties properties ) {
364313 Properties adminClientConfig = new Properties (properties );
365314 // include TLS config name if it has been configured
0 commit comments