- The `ChatBackendController` stores the `ChatHome`s in an array.
- Reintroduced a `ChatRoomFactory`
@Bean
public ChatHome chatHome(ChatHomeService chatHomeService)
{
- return new ChatHome(chatHomeService);
+ return new ChatHome(chatHomeService, 0);
}
@Bean
import de.juplo.kafka.chat.backend.domain.ChatHome;
import de.juplo.kafka.chat.backend.domain.ChatRoom;
+import de.juplo.kafka.chat.backend.domain.ChatRoomFactory;
import de.juplo.kafka.chat.backend.persistence.StorageStrategy;
import lombok.RequiredArgsConstructor;
import org.springframework.http.codec.ServerSentEvent;
@RequiredArgsConstructor
public class ChatBackendController
{
- private final ChatHome chatHome;
+ private final ChatHome[] chatHomes;
+ private final ShardingStrategy selectionStrategy;
+ private final ChatRoomFactory factory;
private final StorageStrategy storageStrategy;
@PostMapping("create")
public Mono<ChatRoomTo> create(@RequestBody String name)
{
- return chatHome.createChatroom(name).map(ChatRoomTo::from);
+ UUID chatRoomId = UUID.randomUUID();
+ return factory
+ .createChatRoom(chatRoomId, name)
+ .flatMap(chatRoom -> chatHomes[chatRoom.getShard()].putChatRoom(chatRoom))
+ .map(ChatRoomTo::from);
}
@GetMapping("list")
public Flux<ChatRoomTo> list()
{
- return chatHome.getChatRooms().map(chatroom -> ChatRoomTo.from(chatroom));
+ return Flux
+ .fromArray(chatHomes)
+ .flatMap(chatHome -> chatHome.getChatRooms())
+ .map(chatroom -> ChatRoomTo.from(chatroom));
}
@GetMapping("{chatroomId}/list")
public Flux<MessageTo> list(@PathVariable UUID chatroomId)
{
- return chatHome
+ int shard = selectionStrategy.selectShard(chatroomId);
+ return chatHomes[shard]
.getChatRoom(chatroomId)
.flatMapMany(chatroom -> chatroom
.getMessages()
@GetMapping("{chatroomId}")
public Mono<ChatRoomTo> get(@PathVariable UUID chatroomId)
{
- return chatHome.getChatRoom(chatroomId).map(chatroom -> ChatRoomTo.from(chatroom));
+ int shard = selectionStrategy.selectShard(chatroomId);
+ return chatHomes[shard]
+ .getChatRoom(chatroomId)
+ .map(chatroom -> ChatRoomTo.from(chatroom));
}
@PutMapping("{chatroomId}/{username}/{messageId}")
@PathVariable Long messageId,
@RequestBody String text)
{
+ int shard = selectionStrategy.selectShard(chatroomId);
return
- chatHome
+ chatHomes[shard]
.getChatRoom(chatroomId)
.flatMap(chatroom -> put(chatroom, username, messageId, text));
}
@PathVariable String username,
@PathVariable Long messageId)
{
+ int shard = selectionStrategy.selectShard(chatroomId);
return
- chatHome
+ chatHomes[shard]
.getChatRoom(chatroomId)
.flatMap(chatroom -> get(chatroom, username, messageId));
}
@GetMapping(path = "{chatroomId}/listen")
public Flux<ServerSentEvent<MessageTo>> listen(@PathVariable UUID chatroomId)
{
- return chatHome
+ int shard = selectionStrategy.selectShard(chatroomId);
+ return chatHomes[shard]
.getChatRoom(chatroomId)
.flatMapMany(chatroom -> listen(chatroom));
}
@PostMapping("/store")
public void store()
{
- storageStrategy.write(chatHome.getChatRooms());
+ for (int shard = 0; shard < chatHomes.length; shard++)
+ storageStrategy.write(chatHomes[shard].getChatRooms());
}
}
{
private UUID id;
private String name;
+ private int shard;
public static ChatRoomTo from(ChatRoom chatroom)
{
- ChatRoomTo info = new ChatRoomTo();
- info.id = chatroom.getId();
- info.name = chatroom.getName();
- return info;
+ ChatRoomTo to = new ChatRoomTo();
+ to.id = chatroom.getId();
+ to.name = chatroom.getName();
+ to.shard = chatroom.getShard();
+ return to;
}
}
--- /dev/null
+package de.juplo.kafka.chat.backend.api;
+
+import java.util.UUID;
+
+
+public interface ShardingStrategy
+{
+ int selectShard(UUID chatRoomId);
+}
public class ChatHome
{
private final ChatHomeService service;
+ private final int shard;
- public Mono<ChatRoom> createChatroom(String name)
+ public Mono<ChatRoom> putChatRoom(ChatRoom chatRoom)
{
- return service.createChatRoom(UUID.randomUUID(), name);
+ return service.putChatRoom(chatRoom);
}
public Mono<ChatRoom> getChatRoom(UUID id)
{
return service
- .getChatRoom(id)
+ .getChatRoom(shard, id)
.switchIfEmpty(Mono.error(() -> new UnknownChatroomException(id)));
}
public Flux<ChatRoom> getChatRooms()
{
- return service.getChatRooms();
+ return service.getChatRooms(shard);
}
}
public interface ChatHomeService<T extends ChatRoomService>
{
- Mono<ChatRoom> createChatRoom(UUID id, String name);
- Mono<ChatRoom> getChatRoom(UUID id);
- Flux<ChatRoom> getChatRooms();
+ Mono<ChatRoom> putChatRoom(ChatRoom chatRoom);
+ Mono<ChatRoom> getChatRoom(int shard, UUID id);
+ Flux<ChatRoom> getChatRooms(int shard);
}
private final UUID id;
@Getter
private final String name;
+ @Getter
+ private final int shard;
private final Clock clock;
private final ChatRoomService service;
private final int bufferSize;
private Sinks.Many<Message> sink;
+
public ChatRoom(
UUID id,
String name,
+ int shard,
Clock clock,
ChatRoomService service,
int bufferSize)
{
this.id = id;
this.name = name;
+ this.shard = shard;
this.clock = clock;
this.service = service;
this.bufferSize = bufferSize;
+ // @RequiredArgsConstructor unfortunately not possible, because
+ // the `bufferSize` is not set, if `createSink()` is called
+ // from the variable declaration!
this.sink = createSink();
}
--- /dev/null
+package de.juplo.kafka.chat.backend.domain;
+
+import reactor.core.publisher.Mono;
+
+import java.util.UUID;
+
+
+public interface ChatRoomFactory
+{
+ Mono<ChatRoom> createChatRoom(UUID id, String name);
+}
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
-import java.time.Clock;
import java.util.HashMap;
-import java.util.LinkedHashMap;
import java.util.Map;
import java.util.UUID;
@Slf4j
public class InMemoryChatHomeService implements ChatHomeService<InMemoryChatRoomService>
{
- private final Map<UUID, ChatRoom> chatrooms;
- private final Clock clock;
- private final int bufferSize;
+ private final Map<UUID, ChatRoom>[] chatrooms;
- public InMemoryChatHomeService(
- Flux<ChatRoom> chatroomFlux,
- Clock clock,
- int bufferSize)
+ public InMemoryChatHomeService(int numShards, Flux<ChatRoom> chatroomFlux)
{
- log.debug("Creating InMemoryChatHomeService with buffer-size {} (for created ChatRoom's)", bufferSize);
- this.chatrooms = new HashMap<>();
- chatroomFlux.toStream().forEach(chatroom -> chatrooms.put(chatroom.getId(), chatroom));
- this.clock = clock;
- this.bufferSize = bufferSize;
+ log.debug("Creating InMemoryChatHomeService");
+ this.chatrooms = new Map[numShards];
+ for (int shard = 0; shard < numShards; shard++)
+ chatrooms[shard] = new HashMap<>();
+ chatroomFlux
+ .toStream()
+ .forEach(chatroom -> chatrooms[chatroom.getShard()].put(chatroom.getId(), chatroom));
}
@Override
- public Mono<ChatRoom> createChatRoom(UUID id, String name)
+ public Mono<ChatRoom> putChatRoom(ChatRoom chatRoom)
{
- InMemoryChatRoomService service =
- new InMemoryChatRoomService(new LinkedHashMap<>());
- ChatRoom chatRoom = new ChatRoom(id, name, clock, service, bufferSize);
- chatrooms.put(chatRoom.getId(), chatRoom);
+ chatrooms[chatRoom.getShard()].put(chatRoom.getId(), chatRoom);
return Mono.just(chatRoom);
}
@Override
- public Mono<ChatRoom> getChatRoom(UUID id)
+ public Mono<ChatRoom> getChatRoom(int shard, UUID id)
{
- return Mono.justOrEmpty(chatrooms.get(id));
+ return Mono.justOrEmpty(chatrooms[shard].get(id));
}
@Override
- public Flux<ChatRoom> getChatRooms()
+ public Flux<ChatRoom> getChatRooms(int shard)
{
- return Flux.fromStream(chatrooms.values().stream());
+ return Flux.fromStream(chatrooms[shard].values().stream());
}
}
--- /dev/null
+package de.juplo.kafka.chat.backend.persistence.inmemory;
+
+import de.juplo.kafka.chat.backend.api.ShardingStrategy;
+import de.juplo.kafka.chat.backend.domain.ChatRoom;
+import de.juplo.kafka.chat.backend.domain.ChatRoomFactory;
+import de.juplo.kafka.chat.backend.domain.ChatRoomService;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
+
+import java.time.Clock;
+import java.util.UUID;
+
+
+@RequiredArgsConstructor
+@Slf4j
+public class InMemoryChatRoomFactory implements ChatRoomFactory
+{
+ private final ShardingStrategy shardingStrategy;
+ private final Clock clock;
+ private final int bufferSize;
+
+
+ @Override
+ public Mono<ChatRoom> createChatRoom(UUID id, String name)
+ {
+ log.info("Creating ChatRoom with buffer-size {}", bufferSize);
+ int shard = shardingStrategy.selectShard(id);
+ ChatRoomService service = new InMemoryChatRoomService(Flux.empty());
+ return Mono.just(new ChatRoom(id, name, shard, clock, service, bufferSize));
+ }
+}
private final LinkedHashMap<Message.MessageKey, Message> messages;
- public InMemoryChatRoomService(LinkedHashMap<Message.MessageKey, Message> messages)
- {
- this.messages = messages;
- }
-
public InMemoryChatRoomService(Flux<Message> messageFlux)
{
log.debug("Creating InMemoryChatRoomService");
package de.juplo.kafka.chat.backend.persistence.inmemory;
import de.juplo.kafka.chat.backend.ChatBackendProperties;
+import de.juplo.kafka.chat.backend.api.ShardingStrategy;
import de.juplo.kafka.chat.backend.persistence.StorageStrategy;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
public class InMemoryServicesConfiguration
{
@Bean
- InMemoryChatHomeService chatHomeService(
- StorageStrategy storageStrategy,
+ InMemoryChatHomeService chatHomeService(StorageStrategy storageStrategy)
+ {
+ return new InMemoryChatHomeService(1, storageStrategy.read());
+ }
+
+ @Bean
+ InMemoryChatRoomFactory chatRoomFactory(
+ ShardingStrategy strategy,
Clock clock,
ChatBackendProperties properties)
{
- return new InMemoryChatHomeService(
- storageStrategy.read(),
+ return new InMemoryChatRoomFactory(
+ strategy,
clock,
properties.getChatroomBufferSize());
}
+
+ @Bean
+ ShardingStrategy shardingStrategy()
+ {
+ return chatRoomId -> 0;
+ }
}
.map(chatRoomTo -> new ChatRoom(
chatRoomTo.getId(),
chatRoomTo.getName(),
+ chatRoomTo.getShard(),
clock,
factory.create(readMessages(chatRoomTo)),
bufferSize));
@Id
private String id;
private String name;
+ private int shard;
private List<MessageTo> messages;
public static ChatRoomTo from(ChatRoom chatroom)
return new ChatRoomTo(
chatroom.getId().toString(),
chatroom.getName(),
+ chatroom.getShard(),
chatroom
.getMessages()
.map(MessageTo::from)
.map(chatRoomTo -> new ChatRoom(
UUID.fromString(chatRoomTo.getId()),
chatRoomTo.getName(),
+ chatRoomTo.getShard(),
clock,
factory.create(
Flux
{
// Given
UUID chatroomId = UUID.randomUUID();
- when(chatHomeService.getChatRoom(any(UUID.class))).thenReturn(Mono.empty());
+ when(chatHomeService.getChatRoom(anyInt(), any(UUID.class))).thenReturn(Mono.empty());
// When
WebTestClient.ResponseSpec responseSpec = client
{
// Given
UUID chatroomId = UUID.randomUUID();
- when(chatHomeService.getChatRoom(any(UUID.class))).thenReturn(Mono.empty());
+ when(chatHomeService.getChatRoom(anyInt(), any(UUID.class))).thenReturn(Mono.empty());
// When
WebTestClient.ResponseSpec responseSpec = client
UUID chatroomId = UUID.randomUUID();
String username = "foo";
Long messageId = 66l;
- when(chatHomeService.getChatRoom(any(UUID.class))).thenReturn(Mono.empty());
+ when(chatHomeService.getChatRoom(anyInt(), any(UUID.class))).thenReturn(Mono.empty());
// When
WebTestClient.ResponseSpec responseSpec = client
UUID chatroomId = UUID.randomUUID();
String username = "foo";
Long messageId = 66l;
- when(chatHomeService.getChatRoom(any(UUID.class))).thenReturn(Mono.empty());
+ when(chatHomeService.getChatRoom(anyInt(), any(UUID.class))).thenReturn(Mono.empty());
// When
WebTestClient.ResponseSpec responseSpec = client
{
// Given
UUID chatroomId = UUID.randomUUID();
- when(chatHomeService.getChatRoom(any(UUID.class))).thenReturn(Mono.empty());
+ when(chatHomeService.getChatRoom(anyInt(), any(UUID.class))).thenReturn(Mono.empty());
// When
WebTestClient.ResponseSpec responseSpec = client
ChatRoom chatRoom = new ChatRoom(
chatroomId,
"Test-ChatRoom",
+ 0,
Clock.systemDefaultZone(),
chatRoomService, 8);
- when(chatHomeService.getChatRoom(any(UUID.class))).thenReturn(Mono.just(chatRoom));
+ when(chatHomeService.getChatRoom(anyInt(), any(UUID.class))).thenReturn(Mono.just(chatRoom));
Message existingMessage = new Message(
key,
serialNumberExistingMessage,
ChatRoom chatRoom = new ChatRoom(
chatroomId,
"Test-ChatRoom",
+ 0,
Clock.systemDefaultZone(),
chatRoomService, 8);
- when(chatHomeService.getChatRoom(any(UUID.class)))
+ when(chatHomeService.getChatRoom(anyInt(), any(UUID.class)))
.thenReturn(Mono.just(chatRoom));
when(chatRoomService.getMessage(any(Message.MessageKey.class)))
.thenReturn(Mono.empty());
import java.util.UUID;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static pl.rzrz.assertj.reactor.Assertions.assertThat;
ChatRoom chatRoom = new ChatRoom(
UUID.randomUUID(),
"Foo",
+ 0,
Clock.systemDefaultZone(),
mock(ChatRoomService.class),
8);
- when(chatHomeService.getChatRoom(any(UUID.class))).thenReturn(Mono.just(chatRoom));
- ChatHome chatHome = new ChatHome(chatHomeService);
+ when(chatHomeService.getChatRoom(anyInt(), any(UUID.class))).thenReturn(Mono.just(chatRoom));
+ ChatHome chatHome = new ChatHome(chatHomeService, 0);
// When
Mono<ChatRoom> mono = chatHome.getChatRoom(chatRoom.getId());
{
// Given
ChatHomeService chatHomeService = mock(ChatHomeService.class);
- when(chatHomeService.getChatRoom(any(UUID.class))).thenReturn(Mono.empty());
- ChatHome chatHome = new ChatHome(chatHomeService);
+ when(chatHomeService.getChatRoom(anyInt(), any(UUID.class))).thenReturn(Mono.empty());
+ ChatHome chatHome = new ChatHome(chatHomeService, 0);
// When
Mono<ChatRoom> mono = chatHome.getChatRoom(UUID.randomUUID());
String user = "foo";
Long messageId = 1l;
ChatRoomService chatRoomService = mock(ChatRoomService.class);
- ChatRoom chatRoom = new ChatRoom(UUID.randomUUID(), "Foo", Clock.systemDefaultZone(), chatRoomService, 8);
+ ChatRoom chatRoom = new ChatRoom(
+ UUID.randomUUID(),
+ "Foo",
+ 0,
+ Clock.systemDefaultZone(),
+ chatRoomService,
+ 8);
Message.MessageKey key = Message.MessageKey.of(user, messageId);
LocalDateTime timestamp = LocalDateTime.now();
Message message = new Message(key, 0l, timestamp, "Bar");
String user = "foo";
Long messageId = 1l;
ChatRoomService chatRoomService = mock(ChatRoomService.class);
- ChatRoom chatRoom = new ChatRoom(UUID.randomUUID(), "Foo", Clock.systemDefaultZone(), chatRoomService, 8);
+ ChatRoom chatRoom = new ChatRoom(
+ UUID.randomUUID(),
+ "Foo",
+ 0,
+ Clock.systemDefaultZone(),
+ chatRoomService,
+ 8);
when(chatRoomService.getMessage(any(Message.MessageKey.class))).thenReturn(Mono.empty());
// When
String user = "foo";
Long messageId = 1l;
ChatRoomService chatRoomService = mock(ChatRoomService.class);
- ChatRoom chatRoom = new ChatRoom(UUID.randomUUID(), "Foo", Clock.systemDefaultZone(), chatRoomService, 8);
+ ChatRoom chatRoom = new ChatRoom(
+ UUID.randomUUID(),
+ "Foo",
+ 0,
+ Clock.systemDefaultZone(),
+ chatRoomService,
+ 8);
Message.MessageKey key = Message.MessageKey.of(user, messageId);
Clock now = Clock.fixed(Instant.now(), ZoneId.systemDefault());
LocalDateTime timestamp = LocalDateTime.now(now);
String user = "foo";
Long messageId = 1l;
ChatRoomService chatRoomService = mock(ChatRoomService.class);
- ChatRoom chatRoom = new ChatRoom(UUID.randomUUID(), "Foo", Clock.systemDefaultZone(), chatRoomService, 8);
+ ChatRoom chatRoom = new ChatRoom(
+ UUID.randomUUID(),
+ "Foo",
+ 0,
+ Clock.systemDefaultZone(),
+ chatRoomService,
+ 8);
Message.MessageKey key = Message.MessageKey.of(user, messageId);
Clock now = Clock.fixed(Instant.now(), ZoneId.systemDefault());
LocalDateTime timestamp = LocalDateTime.now(now);
String user = "foo";
Long messageId = 1l;
ChatRoomService chatRoomService = mock(ChatRoomService.class);
- ChatRoom chatRoom = new ChatRoom(UUID.randomUUID(), "Foo", Clock.systemDefaultZone(), chatRoomService, 8);
+ ChatRoom chatRoom = new ChatRoom(
+ UUID.randomUUID(),
+ "Foo",
+ 0,
+ Clock.systemDefaultZone(),
+ chatRoomService,
+ 8);
Message.MessageKey key = Message.MessageKey.of(user, messageId);
Clock now = Clock.fixed(Instant.now(), ZoneId.systemDefault());
LocalDateTime timestamp = LocalDateTime.now(now);
package de.juplo.kafka.chat.backend.persistence;
-import de.juplo.kafka.chat.backend.domain.ChatHome;
-import de.juplo.kafka.chat.backend.domain.ChatHomeService;
-import de.juplo.kafka.chat.backend.domain.ChatRoom;
-import de.juplo.kafka.chat.backend.domain.Message;
+import de.juplo.kafka.chat.backend.domain.*;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import java.util.List;
+import java.util.UUID;
import java.util.function.Supplier;
import static pl.rzrz.assertj.reactor.Assertions.*;
public abstract class AbstractStorageStrategyIT
{
protected ChatHome chathome;
+ protected ChatRoomFactory chatRoomFactory;
protected abstract StorageStrategy getStorageStrategy();
protected abstract Supplier<ChatHomeService> getChatHomeServiceSupplier();
+ protected abstract ChatRoomFactory getChatRoomFactory();
protected void start()
{
- chathome = new ChatHome(getChatHomeServiceSupplier().get());
+ chathome = new ChatHome(getChatHomeServiceSupplier().get(), 0);
+ chatRoomFactory = getChatRoomFactory();
}
protected void stop()
assertThat(chathome.getChatRooms().toStream()).hasSize(0);
- ChatRoom chatroom = chathome.createChatroom("FOO").block();
+ UUID chatRoomId = UUID.randomUUID();
+ ChatRoom chatroom = chatRoomFactory.createChatRoom(chatRoomId, "FOO").block();
+ chathome.putChatRoom(chatroom);
Message m1 = chatroom.addMessage(1l,"peter", "Hallo, ich heiße Peter!").block();
Message m2 = chatroom.addMessage(1l, "ute", "Ich bin Ute...").block();
Message m3 = chatroom.addMessage(2l, "peter", "Willst du mit mir gehen?").block();
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
+import de.juplo.kafka.chat.backend.api.ShardingStrategy;
import de.juplo.kafka.chat.backend.domain.ChatHomeService;
+import de.juplo.kafka.chat.backend.domain.ChatRoomFactory;
+import de.juplo.kafka.chat.backend.persistence.inmemory.InMemoryChatRoomFactory;
import de.juplo.kafka.chat.backend.persistence.storage.files.FilesStorageStrategy;
import de.juplo.kafka.chat.backend.persistence.inmemory.InMemoryChatHomeService;
import de.juplo.kafka.chat.backend.persistence.inmemory.InMemoryChatRoomService;
@Override
protected Supplier<ChatHomeService> getChatHomeServiceSupplier()
{
- return () -> new InMemoryChatHomeService(getStorageStrategy().read(), clock, 8);
+ return () -> new InMemoryChatHomeService(1, getStorageStrategy().read());
+ }
+
+ @Override
+ protected ChatRoomFactory getChatRoomFactory()
+ {
+ ShardingStrategy strategy = chatRoomId -> 0;
+ return new InMemoryChatRoomFactory(strategy, clock, 8);
}
@BeforeEach
package de.juplo.kafka.chat.backend.persistence;
+import de.juplo.kafka.chat.backend.api.ShardingStrategy;
import de.juplo.kafka.chat.backend.domain.ChatHomeService;
+import de.juplo.kafka.chat.backend.domain.ChatRoomFactory;
import de.juplo.kafka.chat.backend.persistence.inmemory.InMemoryChatHomeService;
import de.juplo.kafka.chat.backend.persistence.InMemoryWithMongoDbStorageStrategyIT.DataSourceInitializer;
+import de.juplo.kafka.chat.backend.persistence.inmemory.InMemoryChatRoomFactory;
import de.juplo.kafka.chat.backend.persistence.inmemory.InMemoryChatRoomService;
import de.juplo.kafka.chat.backend.persistence.storage.mongodb.ChatRoomRepository;
import de.juplo.kafka.chat.backend.persistence.storage.mongodb.MongoDbStorageStrategy;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.test.context.support.TestPropertySourceUtils;
-import org.testcontainers.containers.BindMode;
import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.output.Slf4jLogConsumer;
import org.testcontainers.junit.jupiter.Container;
@Override
protected Supplier<ChatHomeService> getChatHomeServiceSupplier()
{
- return () -> new InMemoryChatHomeService(getStorageStrategy().read(), clock, 8);
+ return () -> new InMemoryChatHomeService(1, getStorageStrategy().read());
}
+ @Override
+ protected ChatRoomFactory getChatRoomFactory()
+ {
+ ShardingStrategy strategy = chatRoomId -> 0;
+ return new InMemoryChatRoomFactory(strategy, clock, 8);
+ }
@TestConfiguration
static class InMemoryWithMongoDbStorageStrategyITConfig