This repository has been archived by the owner on Aug 30, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* The limit is enforced on 2 places 1. with the `ConversationRepoListener`: required when a Conversation with more as the maximum allowed number of conversations is directly added to the Repository 2. with a `$slice` command in the update of `appendMessage(..)` of the `ConversationRepository` * The limit is configured by `smarti.storage.mongodb.maxConvMsg` the default is `5000` * configuration changes are applied only on the next update to an conversation. This is sufficient as this limit is intended to prevent Mongo Documents getting over the limit of 16MByte * Added a UnitTest for the MongoRepository that validates this feature. For testing the limit is set to `50` messages
- Loading branch information
Showing
7 changed files
with
192 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
46 changes: 46 additions & 0 deletions
46
core/src/main/java/io/redlink/smarti/repositories/ConversationRepoListener.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
package io.redlink.smarti.repositories; | ||
|
||
import java.util.Iterator; | ||
|
||
import org.springframework.data.mongodb.core.mapping.event.AbstractMongoEventListener; | ||
import org.springframework.data.mongodb.core.mapping.event.BeforeConvertEvent; | ||
import org.springframework.stereotype.Component; | ||
|
||
import io.redlink.smarti.model.Conversation; | ||
import io.redlink.smarti.model.Message; | ||
|
||
/** | ||
* Mongo application event listener for {@link Conversation}s that ensures that | ||
* save and update operations to not store {@link Conversation}s with more as | ||
* {@link ConversationRepository#DEFAULT_MAX_MESSAGES_PER_CONVERSATION} messages! | ||
* | ||
* see <a href="https://github.com/redlink-gmbh/smarti/issues/281">#281</a> for details | ||
* | ||
* @author Rupert Westenthaler | ||
* | ||
*/ | ||
@Component | ||
public class ConversationRepoListener extends AbstractMongoEventListener<Conversation> { | ||
|
||
|
||
private final MongoConversationStorageConfig config; | ||
|
||
public ConversationRepoListener(MongoConversationStorageConfig config){ | ||
this.config = config; | ||
} | ||
|
||
@Override | ||
public void onBeforeConvert(BeforeConvertEvent<Conversation> event) { | ||
Conversation conversation = event.getSource(); | ||
int numMsg = conversation.getMessages().size(); | ||
if(numMsg > config.getMaxConvMsg()){ | ||
int numRemove = numMsg - config.getMaxConvMsg(); | ||
//remove messages from the front (oldest) until the limit of messages is reached | ||
Iterator<Message> it = conversation.getMessages().iterator(); | ||
for(int i = 0; i < numRemove && it.hasNext(); i++){ | ||
it.next(); | ||
it.remove(); | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
27 changes: 27 additions & 0 deletions
27
core/src/main/java/io/redlink/smarti/repositories/MongoConversationStorageConfig.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
package io.redlink.smarti.repositories; | ||
|
||
import org.springframework.boot.context.properties.ConfigurationProperties; | ||
|
||
@ConfigurationProperties(prefix="smarti.storage.mongodb") | ||
public class MongoConversationStorageConfig { | ||
|
||
/** | ||
* MongoBB has a 16MByte document size limit. So we need to limit the number of messages | ||
* stored with a conversation to ensure that we keep under that limit. | ||
* | ||
* Limiting the number of messages to 5000 will work if we need less as 400chars to represent | ||
* single messages. | ||
*/ //#2281 | ||
public static final int DEFAULT_MAX_MESSAGES_PER_CONVERSATION = 5000; | ||
|
||
int maxConvMsg = DEFAULT_MAX_MESSAGES_PER_CONVERSATION; | ||
|
||
|
||
public int getMaxConvMsg() { | ||
return maxConvMsg; | ||
} | ||
|
||
public void setMaxConvMsg(int maxConvMsg) { | ||
this.maxConvMsg = maxConvMsg; | ||
} | ||
} |
97 changes: 97 additions & 0 deletions
97
core/src/test/java/io/redlink/smarti/repositories/ConversationRepositoryTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
package io.redlink.smarti.repositories; | ||
|
||
import java.util.Arrays; | ||
import java.util.Date; | ||
|
||
import org.bson.types.ObjectId; | ||
import org.junit.Assert; | ||
import org.junit.Test; | ||
import org.springframework.beans.factory.annotation.Autowired; | ||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration; | ||
import org.springframework.data.mongodb.repository.config.EnableMongoRepositories; | ||
import org.springframework.test.context.ContextConfiguration; | ||
|
||
import io.redlink.smarti.model.Conversation; | ||
import io.redlink.smarti.model.ConversationMeta.Status; | ||
import io.redlink.smarti.model.Message; | ||
import io.redlink.smarti.model.Message.Origin; | ||
import io.redlink.smarti.model.User; | ||
import io.redlink.smarti.test.SpringServiceTest; | ||
|
||
@ContextConfiguration(classes={ConversationRepoListener.class}) | ||
@EnableMongoRepositories(basePackageClasses={ConversationRepository.class}) | ||
@EnableAutoConfiguration | ||
public class ConversationRepositoryTest extends SpringServiceTest { | ||
|
||
|
||
@Autowired | ||
private ConversationRepository conversationRepo; | ||
|
||
|
||
@Test | ||
public void testMessageLimit() throws Exception { | ||
ObjectId owner = new ObjectId(); | ||
Conversation conv = new Conversation(); | ||
conv.setOwner(owner); | ||
|
||
conv.getContext().setDomain("test"); | ||
conv.getContext().setContextType("test"); | ||
conv.getContext().setEnvironment("test", "test"); | ||
|
||
User user0 = new User(); | ||
user0.setDisplayName("Test Dummy"); | ||
user0.setEmail("[email protected]"); | ||
user0.setHomeTown("Testhausen"); | ||
conv.setUser(user0); | ||
|
||
User user1 = new User(); | ||
user1.setDisplayName("Maria Testament"); | ||
user1.setEmail("[email protected]"); | ||
user1.setHomeTown("Antesten"); | ||
|
||
conv.getMeta().setStatus(Status.New); | ||
conv.getMeta().setProperty("test", Arrays.asList("test1","test2","test3")); | ||
|
||
for(int i=0; i < 55 ; i++){ | ||
Message message = new Message("msg-"+i); | ||
message.setOrigin(Origin.User); | ||
message.setUser(i%2 == 0 ? user0 : user1); | ||
message.setTime(new Date()); | ||
message.setContent("This is the " + (i + 1) + "message of this conversation"); | ||
conv.getMessages().add(message); | ||
} | ||
|
||
//now save the conversation in the Repository | ||
Conversation created = conversationRepo.save(conv); | ||
Assert.assertNotNull(created.getId()); | ||
//as the message limit is set to 50 we expect the first 5 Messages to be sliced | ||
Assert.assertEquals(50, created.getMessages().size()); | ||
Assert.assertEquals("msg-5", conv.getMessages().get(0).getId()); | ||
Assert.assertEquals("msg-54", created.getMessages().get(created.getMessages().size() - 1).getId()); | ||
|
||
//now lets append a message | ||
Message appended = new Message("appended-0"); | ||
appended.setOrigin(Origin.User); | ||
appended.setUser(user1); | ||
appended.setContent("This is the first appended Message"); | ||
Conversation updated = conversationRepo.appendMessage(created, appended); | ||
Assert.assertEquals(50, updated.getMessages().size()); | ||
Assert.assertEquals("msg-6", updated.getMessages().get(0).getId()); | ||
Assert.assertEquals("appended-0", updated.getMessages().get(updated.getMessages().size() - 1).getId()); | ||
|
||
//lets delete a message and append an other | ||
Assert.assertTrue(conversationRepo.deleteMessage(updated.getId(), "msg-10")); | ||
updated = conversationRepo.findOne(updated.getId()); | ||
Assert.assertEquals(49, updated.getMessages().size()); | ||
appended = new Message("appended-1"); | ||
appended.setOrigin(Origin.User); | ||
appended.setUser(user0); | ||
appended.setContent("This is the second appended Message"); | ||
updated = conversationRepo.appendMessage(updated, appended); | ||
Assert.assertEquals(50, updated.getMessages().size()); | ||
Assert.assertEquals("msg-6", updated.getMessages().get(0).getId()); | ||
Assert.assertEquals("appended-1", updated.getMessages().get(updated.getMessages().size() - 1).getId()); | ||
|
||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters