1 package de.juplo.kafka.chat.backend.persistence.kafka;
3 import de.juplo.kafka.chat.backend.ChatBackendProperties;
4 import de.juplo.kafka.chat.backend.ChatBackendProperties.ShardingStrategyType;
5 import de.juplo.kafka.chat.backend.domain.ChatHome;
6 import de.juplo.kafka.chat.backend.domain.ShardedChatHome;
7 import de.juplo.kafka.chat.backend.domain.ShardingStrategy;
8 import de.juplo.kafka.chat.backend.domain.SimpleChatHome;
9 import de.juplo.kafka.chat.backend.persistence.KafkaLikeShardingStrategy;
10 import de.juplo.kafka.chat.backend.persistence.inmemory.InMemoryChatHomeService;
11 import de.juplo.kafka.chat.backend.persistence.inmemory.InMemoryChatRoomFactory;
12 import lombok.extern.slf4j.Slf4j;
13 import org.apache.kafka.clients.consumer.Consumer;
14 import org.apache.kafka.clients.producer.Producer;
15 import org.springframework.beans.factory.annotation.Autowired;
16 import org.springframework.boot.ApplicationArguments;
17 import org.springframework.boot.ApplicationRunner;
18 import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
19 import org.springframework.context.ConfigurableApplicationContext;
20 import org.springframework.context.annotation.Bean;
21 import org.springframework.context.annotation.Configuration;
22 import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
23 import org.springframework.util.concurrent.ListenableFuture;
25 import java.time.Clock;
26 import java.time.ZoneId;
27 import java.util.Optional;
28 import java.util.concurrent.CompletableFuture;
31 @ConditionalOnProperty(
32 prefix = "chat.backend",
34 havingValue = "kafka")
37 public class KafkaServicesConfiguration implements ApplicationRunner
40 ThreadPoolTaskExecutor taskExecutor;
42 ConfigurableApplicationContext context;
45 ChatMessageChannel chatMessageChannel;
47 CompletableFuture<Optional<Exception>> chatRoomChannelConsumerJob;
48 CompletableFuture<Optional<Exception>> chatMessageChannelConsumerJob;
52 public void run(ApplicationArguments args) throws Exception
54 log.info("Starting the consumer for the ChatRoomChannel");
55 chatRoomChannelConsumerJob = taskExecutor.submitCompletable(chatMessageChannel);
56 chatRoomChannelConsumerJob.thenAccept(exceptionOptional ->
58 exceptionOptional.ifPresent();
59 log.info("SimpleConsumer exited normally, exit-status: {}", exitStatus);
60 SpringApplication.exit(context, () -> exitStatus);
64 log.error("SimpleConsumer exited abnormally!", t);
65 SpringApplication.exit(context, () -> 2);
70 public void shutdown() throws ExecutionException, InterruptedException
72 log.info("Signaling SimpleConsumer to quit its work");
73 kafkaConsumer.wakeup();
74 log.info("Waiting for SimpleConsumer to finish its work");
76 log.info("SimpleConsumer finished its work");
81 ChatHome kafkaChatHome(
82 ShardingStrategy shardingStrategy,
83 ChatMessageChannel chatMessageChannel)
85 return new KafkaChatHome(shardingStrategy, chatMessageChannel);
89 KafkaChatRoomFactory chatRoomFactory(ChatRoomChannel chatRoomChannel)
91 return new KafkaChatRoomFactory(chatRoomChannel);
95 ChatRoomChannel chatRoomChannel(
96 ChatBackendProperties properties,
97 Producer<Integer, ChatRoomTo> chatRoomChannelProducer,
98 Consumer<Integer, ChatRoomTo> chatRoomChannelConsumer,
99 ShardingStrategy shardingStrategy,
100 ChatMessageChannel chatMessageChannel,
103 return new ChatRoomChannel(
104 properties.getKafka().getTopic(),
105 chatRoomChannelProducer,
106 chatRoomChannelConsumer,
110 properties.getChatroomBufferSize());
114 ChatMessageChannel chatMessageChannel(
115 ChatBackendProperties properties,
116 Producer<String, MessageTo> chatMessageChannelProducer,
117 Consumer<String, MessageTo> chatMessageChannelConsumer,
120 return new ChatMessageChannel(
121 properties.getKafka().getTopic(),
122 chatMessageChannelProducer,
123 chatMessageChannelConsumer,
125 properties.getKafka().getNumPartitions());
129 ShardingStrategy shardingStrategy(ChatBackendProperties properties)
131 return new KafkaLikeShardingStrategy(properties.getKafka().getNumPartitions());
137 return ZoneId.systemDefault();