X-Git-Url: https://juplo.de/gitweb/?a=blobdiff_plain;f=src%2Fmain%2Fjava%2Fde%2Fjuplo%2Fkafka%2Fchat%2Fbackend%2Fpersistence%2Fkafka%2FChatMessageChannel.java;h=8294316f497157fd0067054e45bfb9a9bb620595;hb=1416ccc8a9eae999201dbf7c77c4d4906fc9fc24;hp=7b19bb6b1f2584c6246e05a831aa0b68efedbf81;hpb=5c338c58065988f7841c4ab9ee1b193e754da9b9;p=demos%2Fkafka%2Fchat diff --git a/src/main/java/de/juplo/kafka/chat/backend/persistence/kafka/ChatMessageChannel.java b/src/main/java/de/juplo/kafka/chat/backend/persistence/kafka/ChatMessageChannel.java index 7b19bb6b..8294316f 100644 --- a/src/main/java/de/juplo/kafka/chat/backend/persistence/kafka/ChatMessageChannel.java +++ b/src/main/java/de/juplo/kafka/chat/backend/persistence/kafka/ChatMessageChannel.java @@ -18,16 +18,15 @@ import reactor.core.publisher.Mono; import java.time.*; import java.util.*; -import java.util.concurrent.Callable; import java.util.stream.IntStream; @Slf4j -public class ChatMessageChannel implements Callable>, ConsumerRebalanceListener +public class ChatMessageChannel implements Runnable, ConsumerRebalanceListener { private final String topic; - private final Producer producer; - private final Consumer consumer; + private final Producer producer; + private final Consumer consumer; private final ZoneId zoneId; private final int numShards; private final boolean[] isShardOwned; @@ -43,8 +42,8 @@ public class ChatMessageChannel implements Callable>, Consum public ChatMessageChannel( String topic, - Producer producer, - Consumer consumer, + Producer producer, + Consumer consumer, ZoneId zoneId, int numShards) { @@ -61,6 +60,9 @@ public class ChatMessageChannel implements Callable>, Consum this.currentOffset = new long[numShards]; this.nextOffset = new long[numShards]; this.chatrooms = new Map[numShards]; + IntStream + .range(0, numShards) + .forEach(shard -> this.chatrooms[shard] = new HashMap<>()); this.shardingStrategy = new KafkaLikeShardingStrategy(numShards); } @@ -76,13 +78,13 @@ public class ChatMessageChannel implements Callable>, Consum ZonedDateTime zdt = ZonedDateTime.of(timestamp, zoneId); return Mono.create(sink -> { - ProducerRecord record = + ProducerRecord record = new ProducerRecord<>( tp.topic(), tp.partition(), zdt.toEpochSecond(), chatRoomId.toString(), - MessageTo.of(key.getUsername(), key.getMessageId(), text)); + ChatMessageTo.of(key.getUsername(), key.getMessageId(), text)); producer.send(record, ((metadata, exception) -> { @@ -153,9 +155,9 @@ public class ChatMessageChannel implements Callable>, Consum } @Override - public Optional call() + public void run() { - consumer.subscribe(List.of(topic)); + consumer.subscribe(List.of(topic), this); running = true; @@ -163,12 +165,12 @@ public class ChatMessageChannel implements Callable>, Consum { try { - ConsumerRecords records = consumer.poll(Duration.ofMinutes(5)); + ConsumerRecords records = consumer.poll(Duration.ofMinutes(5)); log.info("Fetched {} messages", records.count()); if (loadInProgress) { - loadMessages(records); + loadChatRoom(records); if (isLoadingCompleted()) { @@ -191,42 +193,60 @@ public class ChatMessageChannel implements Callable>, Consum log.info("Received WakeupException, exiting!"); running = false; } - catch (Exception e) - { - log.error("Exiting abnormally!"); - return Optional.of(e); - } } log.info("Exiting normally"); - return Optional.empty(); } - void loadMessages(ConsumerRecords records) + void loadChatRoom(ConsumerRecords records) { - for (ConsumerRecord record : records) + for (ConsumerRecord record : records) { - nextOffset[record.partition()] = record.offset() + 1; - UUID chatRoomId = UUID.fromString(record.key()); - MessageTo messageTo = record.value(); + switch (record.value().getType()) + { + case CREATE_CHATROOM_REQUEST: + createChatRoom((CreateChatRoomRequestTo) record.value()); + break; + + case MESSAGE_SENT: + UUID chatRoomId = UUID.fromString(record.key()); + Instant instant = Instant.ofEpochSecond(record.timestamp()); + LocalDateTime timestamp = LocalDateTime.ofInstant(instant, zoneId); + loadChatMessage( + chatRoomId, + timestamp, + record.offset(), + (ChatMessageTo) record.value(), + record.partition()); + break; + } - Message.MessageKey key = Message.MessageKey.of(messageTo.getUser(), messageTo.getId()); + nextOffset[record.partition()] = record.offset() + 1; + } + } - Instant instant = Instant.ofEpochSecond(record.timestamp()); - LocalDateTime timestamp = LocalDateTime.ofInstant(instant, zoneId); + void createChatRoom( + CreateChatRoomRequestTo createChatRoomRequestTo, + int partition) + { + chatrooms[partition].put + } - Message message = new Message(key, record.offset(), timestamp, messageTo.getText()); + void loadChatMessage( + UUID chatRoomId, + LocalDateTime timestamp, + long offset, + ChatMessageTo chatMessageTo, + int partition) + { + Message.MessageKey key = Message.MessageKey.of(chatMessageTo.getUser(), chatMessageTo.getId()); + Message message = new Message(key, offset, timestamp, chatMessageTo.getText()); - ChatRoom chatRoom = chatrooms[record.partition()].get(chatRoomId); - if (chatRoom == null) - { - // Alles pausieren und erst von putChatRoom wieder resumen lassen! - } - KafkaChatRoomService kafkaChatRoomService = - (KafkaChatRoomService) chatRoom.getChatRoomService(); + ChatRoom chatRoom = chatrooms[partition].get(chatRoomId); + KafkaChatRoomService kafkaChatRoomService = + (KafkaChatRoomService) chatRoom.getChatRoomService(); - kafkaChatRoomService.persistMessage(message); - } + kafkaChatRoomService.persistMessage(message); } boolean isLoadingCompleted() @@ -234,11 +254,7 @@ public class ChatMessageChannel implements Callable>, Consum return IntStream .range(0, numShards) .filter(shard -> isShardOwned[shard]) - .mapToObj(shard -> nextOffset[shard] >= currentOffset[shard]) - .collect( - () -> Boolean.TRUE, // TODO: Boolean is immutable - (acc, v) -> Boolean.valueOf(acc && v), // TODO: Boolean is immutable - (a, b) -> Boolean.valueOf(a && b)); // TODO: Boolean is immutable + .allMatch(shard -> nextOffset[shard] >= currentOffset[shard]); } void pauseAllOwnedPartions()