This is an automated email from the ASF dual-hosted git repository.
lizhimins pushed a commit to branch rocketmq-studio
in repository https://gitbox.apache.org/repos/asf/rocketmq-dashboard.git
The following commit(s) were added to refs/heads/rocketmq-studio by this push:
new ec071158 fix: keep instance updates atomic on save failures (#732)
ec071158 is described below
commit ec07115806b8dfd12bcf6ed20a40a19e14ea1b37
Author: Rui <[email protected]>
AuthorDate: Mon Aug 3 11:15:54 2026 +0800
fix: keep instance updates atomic on save failures (#732)
---
.../rocketmq/studio/instance/InstanceService.java | 28 +++++++---
.../studio/instance/InstanceServiceTest.java | 60 +++++++++++++++++++++-
2 files changed, 81 insertions(+), 7 deletions(-)
diff --git
a/server/src/main/java/org/apache/rocketmq/studio/instance/InstanceService.java
b/server/src/main/java/org/apache/rocketmq/studio/instance/InstanceService.java
index 4269c9d9..0e17a59c 100644
---
a/server/src/main/java/org/apache/rocketmq/studio/instance/InstanceService.java
+++
b/server/src/main/java/org/apache/rocketmq/studio/instance/InstanceService.java
@@ -81,21 +81,22 @@ public class InstanceService {
throw new BusinessException(400, "InstanceVO endpoint is
required");
}
+ InstanceVO updated = copyOf(existing);
if (instance.getName() != null) {
- existing.setName(instance.getName());
+ updated.setName(instance.getName());
}
if (instance.getType() != null) {
- existing.setType(instance.getType());
+ updated.setType(instance.getType());
}
if (instance.getEndpoint() != null) {
- existing.setEndpoint(instance.getEndpoint());
+ updated.setEndpoint(instance.getEndpoint());
}
if (instance.getRemark() != null) {
- existing.setRemark(instance.getRemark());
+ updated.setRemark(instance.getRemark());
}
- existing.setUpdatedAt(LocalDateTime.now());
+ updated.setUpdatedAt(LocalDateTime.now());
- return instanceRepository.save(existing);
+ return instanceRepository.save(updated);
}
public void deleteInstance(String id) {
@@ -109,4 +110,19 @@ public class InstanceService {
.orElseThrow(() -> new BusinessException(404, "InstanceVO not
found: " + id));
instanceRepository.deleteById(id);
}
+
+ private InstanceVO copyOf(InstanceVO instance) {
+ InstanceVO copy = InstanceVO.builder()
+ .name(instance.getName())
+ .remark(instance.getRemark())
+ .type(instance.getType())
+ .endpoint(instance.getEndpoint())
+ .topicCount(instance.getTopicCount())
+ .consumerGroupCount(instance.getConsumerGroupCount())
+ .build();
+ copy.setId(instance.getId());
+ copy.setCreatedAt(instance.getCreatedAt());
+ copy.setUpdatedAt(instance.getUpdatedAt());
+ return copy;
+ }
}
diff --git
a/server/src/test/java/org/apache/rocketmq/studio/instance/InstanceServiceTest.java
b/server/src/test/java/org/apache/rocketmq/studio/instance/InstanceServiceTest.java
index 63dcf377..bae0806e 100644
---
a/server/src/test/java/org/apache/rocketmq/studio/instance/InstanceServiceTest.java
+++
b/server/src/test/java/org/apache/rocketmq/studio/instance/InstanceServiceTest.java
@@ -25,6 +25,7 @@ import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
+import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;
@@ -203,13 +204,19 @@ class InstanceServiceTest {
@Test
void updateInstanceShouldMergeFieldsOntoExisting() {
+ LocalDateTime originalCreatedAt = LocalDateTime.of(2025, 1, 2, 3, 4,
5);
+ LocalDateTime originalUpdatedAt = LocalDateTime.of(2025, 2, 3, 4, 5,
6);
InstanceVO existing = InstanceVO.builder()
.name("old-name")
.endpoint("10.0.1.1:8080")
.type(InstanceType.PROXY)
.remark("old remark")
+ .topicCount(7)
+ .consumerGroupCount(3)
.build();
existing.setId("inst-1");
+ existing.setCreatedAt(originalCreatedAt);
+ existing.setUpdatedAt(originalUpdatedAt);
InstanceVO update = InstanceVO.builder()
.name("new-name")
@@ -226,7 +233,58 @@ class InstanceServiceTest {
assertThat(result.getEndpoint()).isEqualTo("10.0.1.1:8080");
assertThat(result.getType()).isEqualTo(InstanceType.PROXY);
assertThat(result.getRemark()).isEqualTo("new remark");
- assertThat(result.getUpdatedAt()).isNotNull();
+ assertThat(result.getTopicCount()).isEqualTo(7);
+ assertThat(result.getConsumerGroupCount()).isEqualTo(3);
+ assertThat(result.getId()).isEqualTo("inst-1");
+ assertThat(result.getCreatedAt()).isEqualTo(originalCreatedAt);
+ assertThat(result.getUpdatedAt()).isAfter(originalUpdatedAt);
+ assertThat(result).isNotSameAs(existing);
+ assertThat(existing.getName()).isEqualTo("old-name");
+ assertThat(existing.getRemark()).isEqualTo("old remark");
+ assertThat(existing.getUpdatedAt()).isEqualTo(originalUpdatedAt);
+ }
+
+ @Test
+ void updateInstanceShouldNotMutateStoredInstanceWhenSaveFails() {
+ LocalDateTime originalCreatedAt = LocalDateTime.of(2025, 1, 2, 3, 4,
5);
+ LocalDateTime originalUpdatedAt = LocalDateTime.of(2025, 2, 3, 4, 5,
6);
+ InstanceVO stored = InstanceVO.builder()
+ .name("old-name")
+ .remark("old remark")
+ .type(InstanceType.PROXY)
+ .endpoint("10.0.1.1:8080")
+ .topicCount(7)
+ .consumerGroupCount(3)
+ .build();
+ stored.setId("inst-1");
+ stored.setCreatedAt(originalCreatedAt);
+ stored.setUpdatedAt(originalUpdatedAt);
+
+ InstanceVO update = InstanceVO.builder()
+ .name("new-name")
+ .remark("new remark")
+ .type(InstanceType.DIRECT)
+ .endpoint("10.0.2.2:10911")
+ .build();
+ update.setId("inst-1");
+
+
when(instanceRepository.findById("inst-1")).thenReturn(Optional.of(stored));
+ when(instanceRepository.save(any(InstanceVO.class)))
+ .thenThrow(new IllegalStateException("storage unavailable"));
+
+ assertThatThrownBy(() -> instanceService.updateInstance(update))
+ .isInstanceOf(IllegalStateException.class)
+ .hasMessage("storage unavailable");
+
+ assertThat(stored.getName()).isEqualTo("old-name");
+ assertThat(stored.getRemark()).isEqualTo("old remark");
+ assertThat(stored.getType()).isEqualTo(InstanceType.PROXY);
+ assertThat(stored.getEndpoint()).isEqualTo("10.0.1.1:8080");
+ assertThat(stored.getTopicCount()).isEqualTo(7);
+ assertThat(stored.getConsumerGroupCount()).isEqualTo(3);
+ assertThat(stored.getId()).isEqualTo("inst-1");
+ assertThat(stored.getCreatedAt()).isEqualTo(originalCreatedAt);
+ assertThat(stored.getUpdatedAt()).isEqualTo(originalUpdatedAt);
}
@Test