WIP:haproxy
[demos/kafka/chat] / src / main / java / de / juplo / kafka / chat / backend / implementation / kafka / DataChannel.java
index 4d5a141..532a3c1 100644 (file)
@@ -25,6 +25,7 @@ import java.util.stream.IntStream;
 @Slf4j
 public class DataChannel implements Runnable, ConsumerRebalanceListener
 {
+  private final String instanceId;
   private final String topic;
   private final Producer<String, AbstractMessageTo> producer;
   private final Consumer<String, AbstractMessageTo> consumer;
@@ -36,6 +37,8 @@ public class DataChannel implements Runnable, ConsumerRebalanceListener
   private final long[] currentOffset;
   private final long[] nextOffset;
   private final Map<UUID, ChatRoomData>[] chatRoomData;
+  private final InfoChannel infoChannel;
+  private final ShardingPublisherStrategy shardingPublisherStrategy;
 
   private boolean running;
   @Getter
@@ -43,18 +46,23 @@ public class DataChannel implements Runnable, ConsumerRebalanceListener
 
 
   public DataChannel(
+    String instanceId,
     String topic,
     Producer<String, AbstractMessageTo> producer,
     Consumer<String, AbstractMessageTo> dataChannelConsumer,
     ZoneId zoneId,
     int numShards,
     int bufferSize,
-    Clock clock)
+    Clock clock,
+    InfoChannel infoChannel,
+    ShardingPublisherStrategy shardingPublisherStrategy)
   {
     log.debug(
-        "Creating DataChannel for topic {} with {} partitions",
+        "{}: Creating DataChannel for topic {} with {} partitions",
+        instanceId,
         topic,
         numShards);
+    this.instanceId = instanceId;
     this.topic = topic;
     this.consumer = dataChannelConsumer;
     this.producer = producer;
@@ -68,10 +76,9 @@ public class DataChannel implements Runnable, ConsumerRebalanceListener
     this.chatRoomData = new Map[numShards];
     IntStream
         .range(0, numShards)
-        .forEach(shard ->
-        {
-          this.chatRoomData[shard] = new HashMap<>();
-        });
+        .forEach(shard -> this.chatRoomData[shard] = new HashMap<>());
+    this.infoChannel = infoChannel;
+    this.shardingPublisherStrategy = shardingPublisherStrategy;
   }
 
 
@@ -137,6 +144,14 @@ public class DataChannel implements Runnable, ConsumerRebalanceListener
           currentOffset);
 
       consumer.seek(topicPartition, nextOffset[partition]);
+      infoChannel.sendShardAssignedEvent(partition);
+      shardingPublisherStrategy
+          .publishOwnership(partition)
+          .doOnNext(instanceId -> log.info(
+              "Instance {} was published as owner of shard {}",
+              instanceId,
+              partition))
+          .subscribe();
     });
 
     consumer.resume(partitions);
@@ -150,6 +165,7 @@ public class DataChannel implements Runnable, ConsumerRebalanceListener
       int partition = topicPartition.partition();
       isShardOwned[partition] = false;
       log.info("Partition revoked: {} - next={}", partition, nextOffset[partition]);
+      infoChannel.sendShardRevokedEvent(partition);
     });
   }
 
@@ -244,14 +260,9 @@ public class DataChannel implements Runnable, ConsumerRebalanceListener
     Message.MessageKey key = Message.MessageKey.of(chatMessageTo.getUser(), chatMessageTo.getId());
     Message message = new Message(key, offset, timestamp, chatMessageTo.getText());
 
-    ChatRoomData chatRoomData = this.chatRoomData[partition].computeIfAbsent(
-        chatRoomId,
-        (id) ->
-        {
-          log.info("Creating ChatRoom {} with buffer-size {}", id, bufferSize);
-          KafkaChatMessageService service = new KafkaChatMessageService(this, id);
-          return new ChatRoomData(clock, service, bufferSize);
-        });
+    ChatRoomData chatRoomData = this
+        .chatRoomData[partition]
+        .computeIfAbsent(chatRoomId, this::computeChatRoomData);
     KafkaChatMessageService kafkaChatRoomService =
         (KafkaChatMessageService) chatRoomData.getChatRoomService();
 
@@ -293,9 +304,19 @@ public class DataChannel implements Runnable, ConsumerRebalanceListener
 
     if (!isShardOwned[shard])
     {
-      return Mono.error(new ShardNotOwnedException(shard));
+      return Mono.error(new ShardNotOwnedException(instanceId, shard));
     }
 
-    return Mono.justOrEmpty(chatRoomData[shard].get(id));
+    return infoChannel
+        .getChatRoomInfo(id)
+        .map(chatRoomInfo ->
+            chatRoomData[shard].computeIfAbsent(id, this::computeChatRoomData));
+  }
+
+  private ChatRoomData computeChatRoomData(UUID chatRoomId)
+  {
+    log.info("Creating ChatRoom {} with buffer-size {}", chatRoomId, bufferSize);
+    KafkaChatMessageService service = new KafkaChatMessageService(this, chatRoomId);
+    return new ChatRoomData(clock, service, bufferSize);
   }
 }