GH-5123: Add LockRegistry to AbstractMessageGroupStore
Fixes: https://github.com/spring-projects/spring-integration/issues/5123 When `RedisMessageStore`, for example, adds and removes messages, it operates on two keys separately, which may cause problems in multi-threading due to non-atomic operations. Although using Redis to delay messages is not a good idea, the abnormal loss of messages in the logs alerted me when the number of requests was not large. By comparing the logs, the problem that the message group representing the metadata is not consistent with the actual message. A simple solution is to add lock like in the `SimpleMessageStore`, which is also the approach taken in this pull request. * Add `LockRegistry` to `AbstractMessageGroupStore` * Normalize access levels and method name about the lock of `MessageGroupStore` * Add document about the lock of `AbstractMessageGroupStore`
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2024 the original author or authors.
|
||||
* Copyright 2014-2025 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -61,6 +61,7 @@ import org.springframework.util.Assert;
|
||||
*
|
||||
* @author Artem Bilan
|
||||
* @author Adama Sorho
|
||||
* @author Youbin Wu
|
||||
*
|
||||
* @since 4.0
|
||||
*/
|
||||
@@ -201,7 +202,7 @@ public abstract class AbstractConfigurableMongoDbMessageStore extends AbstractMe
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeMessageGroup(Object groupId) {
|
||||
protected void doRemoveMessageGroup(Object groupId) {
|
||||
this.mongoTemplate.remove(groupIdQuery(groupId), this.collectionName);
|
||||
}
|
||||
|
||||
@@ -250,17 +251,17 @@ public abstract class AbstractConfigurableMongoDbMessageStore extends AbstractMe
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeMessagesFromGroup(Object key, Collection<Message<?>> messages) {
|
||||
protected void doRemoveMessagesFromGroup(Object key, Collection<Message<?>> messages) {
|
||||
throw NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setGroupCondition(Object groupId, String condition) {
|
||||
protected void doSetGroupCondition(Object groupId, String condition) {
|
||||
throw NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLastReleasedSequenceNumberForGroup(Object groupId, int sequenceNumber) {
|
||||
protected void doSetLastReleasedSequenceNumberForGroup(Object groupId, int sequenceNumber) {
|
||||
throw NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
@@ -270,7 +271,7 @@ public abstract class AbstractConfigurableMongoDbMessageStore extends AbstractMe
|
||||
}
|
||||
|
||||
@Override
|
||||
public void completeGroup(Object groupId) {
|
||||
protected void doCompleteGroup(Object groupId) {
|
||||
throw NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
@@ -280,7 +281,7 @@ public abstract class AbstractConfigurableMongoDbMessageStore extends AbstractMe
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addMessagesToGroup(Object groupId, Message<?>... messages) {
|
||||
protected void doAddMessagesToGroup(Object groupId, Message<?>... messages) {
|
||||
throw NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2024 the original author or authors.
|
||||
* Copyright 2013-2025 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -54,6 +54,7 @@ import org.springframework.util.Assert;
|
||||
* @author Artem Bilan
|
||||
* @author Gary Russell
|
||||
* @author Ngoc Nhan
|
||||
* @author Youbin Wu
|
||||
*
|
||||
* @since 3.0
|
||||
*/
|
||||
@@ -147,7 +148,7 @@ public class ConfigurableMongoDbMessageStore extends AbstractConfigurableMongoDb
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addMessagesToGroup(Object groupId, Message<?>... messages) {
|
||||
protected void doAddMessagesToGroup(Object groupId, Message<?>... messages) {
|
||||
Assert.notNull(groupId, GROUP_ID_MUST_NOT_BE_NULL);
|
||||
Assert.notNull(messages, "'message' must not be null");
|
||||
|
||||
@@ -183,7 +184,7 @@ public class ConfigurableMongoDbMessageStore extends AbstractConfigurableMongoDb
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeMessagesFromGroup(Object groupId, Collection<Message<?>> messages) {
|
||||
protected void doRemoveMessagesFromGroup(Object groupId, Collection<Message<?>> messages) {
|
||||
Assert.notNull(groupId, GROUP_ID_MUST_NOT_BE_NULL);
|
||||
Assert.notNull(messages, "'messageToRemove' must not be null");
|
||||
|
||||
@@ -215,7 +216,7 @@ public class ConfigurableMongoDbMessageStore extends AbstractConfigurableMongoDb
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeMessageFromGroupById(Object groupId, UUID messageId) {
|
||||
protected boolean doRemoveMessageFromGroupById(Object groupId, UUID messageId) {
|
||||
Assert.notNull(groupId, GROUP_ID_MUST_NOT_BE_NULL);
|
||||
Assert.notNull(messageId, "'messageId' must not be null");
|
||||
Query query =
|
||||
@@ -234,7 +235,7 @@ public class ConfigurableMongoDbMessageStore extends AbstractConfigurableMongoDb
|
||||
}
|
||||
|
||||
@Override
|
||||
public Message<?> pollMessageFromGroup(final Object groupId) {
|
||||
protected Message<?> doPollMessageFromGroup(final Object groupId) {
|
||||
Assert.notNull(groupId, GROUP_ID_MUST_NOT_BE_NULL);
|
||||
|
||||
Sort sort = Sort.by(MessageDocumentFields.LAST_MODIFIED_TIME, MessageDocumentFields.SEQUENCE);
|
||||
@@ -249,17 +250,17 @@ public class ConfigurableMongoDbMessageStore extends AbstractConfigurableMongoDb
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLastReleasedSequenceNumberForGroup(Object groupId, int sequenceNumber) {
|
||||
protected void doSetLastReleasedSequenceNumberForGroup(Object groupId, int sequenceNumber) {
|
||||
updateGroup(groupId, lastModifiedUpdate().set(MessageDocumentFields.LAST_RELEASED_SEQUENCE, sequenceNumber));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setGroupCondition(Object groupId, String condition) {
|
||||
protected void doSetGroupCondition(Object groupId, String condition) {
|
||||
updateGroup(groupId, lastModifiedUpdate().set("condition", condition));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void completeGroup(Object groupId) {
|
||||
protected void doCompleteGroup(Object groupId) {
|
||||
updateGroup(groupId, lastModifiedUpdate().set(MessageDocumentFields.COMPLETE, true));
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2023 the original author or authors.
|
||||
* Copyright 2014-2025 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -44,6 +44,7 @@ import org.springframework.util.Assert;
|
||||
*
|
||||
* @author Artem Bilan
|
||||
* @author Adama Sorho
|
||||
* @author Youbin Wu
|
||||
*
|
||||
* @since 4.0
|
||||
*/
|
||||
@@ -132,7 +133,7 @@ public class MongoDbChannelMessageStore extends AbstractConfigurableMongoDbMessa
|
||||
}
|
||||
|
||||
@Override
|
||||
public Message<?> pollMessageFromGroup(Object groupId) {
|
||||
protected Message<?> doPollMessageFromGroup(Object groupId) {
|
||||
Assert.notNull(groupId, "'groupId' must not be null");
|
||||
|
||||
Sort sort = Sort.by(MessageDocumentFields.LAST_MODIFIED_TIME, MessageDocumentFields.SEQUENCE);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
* Copyright 2002-2025 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -97,6 +97,7 @@ import org.springframework.util.StringUtils;
|
||||
* @author Jodie StJohn
|
||||
* @author Gary Russell
|
||||
* @author Artem Bilan
|
||||
* @author Youbin Wu
|
||||
*
|
||||
* @since 2.1
|
||||
*/
|
||||
@@ -294,7 +295,7 @@ public class MongoDbMessageStore extends AbstractMessageGroupStore
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addMessagesToGroup(Object groupId, Message<?>... messages) {
|
||||
protected void doAddMessagesToGroup(Object groupId, Message<?>... messages) {
|
||||
Assert.notNull(groupId, GROUP_ID_MUST_NOT_BE_NULL);
|
||||
Assert.notNull(messages, "'message' must not be null");
|
||||
Query query = whereGroupIdOrder(groupId);
|
||||
@@ -328,7 +329,7 @@ public class MongoDbMessageStore extends AbstractMessageGroupStore
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeMessagesFromGroup(Object groupId, Collection<Message<?>> messages) {
|
||||
protected void doRemoveMessagesFromGroup(Object groupId, Collection<Message<?>> messages) {
|
||||
Assert.notNull(groupId, GROUP_ID_MUST_NOT_BE_NULL);
|
||||
Assert.notNull(messages, "'messageToRemove' must not be null");
|
||||
|
||||
@@ -367,7 +368,7 @@ public class MongoDbMessageStore extends AbstractMessageGroupStore
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeMessageFromGroupById(Object groupId, UUID messageId) {
|
||||
protected boolean doRemoveMessageFromGroupById(Object groupId, UUID messageId) {
|
||||
Assert.notNull(groupId, GROUP_ID_MUST_NOT_BE_NULL);
|
||||
Assert.notNull(messageId, "'messageId' must not be null");
|
||||
return this.template.remove(whereMessageIdIsAndGroupIdIs(messageId, groupId), this.collectionName)
|
||||
@@ -375,7 +376,7 @@ public class MongoDbMessageStore extends AbstractMessageGroupStore
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeMessageGroup(Object groupId) {
|
||||
protected void doRemoveMessageGroup(Object groupId) {
|
||||
this.template.remove(whereGroupIdIs(groupId), this.collectionName);
|
||||
}
|
||||
|
||||
@@ -395,7 +396,7 @@ public class MongoDbMessageStore extends AbstractMessageGroupStore
|
||||
}
|
||||
|
||||
@Override
|
||||
public Message<?> pollMessageFromGroup(final Object groupId) {
|
||||
protected Message<?> doPollMessageFromGroup(final Object groupId) {
|
||||
Assert.notNull(groupId, GROUP_ID_MUST_NOT_BE_NULL);
|
||||
Query query = whereGroupIdIs(groupId).with(Sort.by(GROUP_UPDATE_TIMESTAMP_KEY, SEQUENCE));
|
||||
MessageWrapper messageWrapper = this.template.findAndRemove(query, MessageWrapper.class, this.collectionName);
|
||||
@@ -415,17 +416,17 @@ public class MongoDbMessageStore extends AbstractMessageGroupStore
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setGroupCondition(Object groupId, String condition) {
|
||||
protected void doSetGroupCondition(Object groupId, String condition) {
|
||||
updateGroup(groupId, lastModifiedUpdate().set("_condition", condition));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLastReleasedSequenceNumberForGroup(Object groupId, int sequenceNumber) {
|
||||
protected void doSetLastReleasedSequenceNumberForGroup(Object groupId, int sequenceNumber) {
|
||||
updateGroup(groupId, lastModifiedUpdate().set(LAST_RELEASED_SEQUENCE_NUMBER, sequenceNumber));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void completeGroup(Object groupId) {
|
||||
protected void doCompleteGroup(Object groupId) {
|
||||
this.updateGroup(groupId, lastModifiedUpdate().set(GROUP_COMPLETE_KEY, true));
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user