This commit is contained in:
2026-08-24 17:15:48 +08:00
parent 132d96a99b
commit 3d8a1fac20
45 changed files with 1250 additions and 35 deletions
+1 -1
View File
@@ -15,7 +15,7 @@
| 按目标区域调度与重试 | `service/OverseasEventDispatcher.java`;`targetRegion=OVERSEAS` 投 Lastleg,`targetRegion=CN` 回投 Firstleg |
| 尾程 HTTP 客户端 | `service/LastlegEventClient.java`、`HttpLastlegEventClient.java` |
| 国内头程 HTTP 客户端 | `service/FirstlegEventClient.java`、`HttpFirstlegEventClient.java`;默认内部入口 `/internal/firstleg/v1/container-events` |
| 人工补投 | `service/EventReplayService.java` |
| 人工补投 | `service/EventReplayService.java`;只允许 `DEAD` 转回 `RETRY`,记录操作人与原因,并保留原 `eventId`、payload 与 `payloadHash` |
| Inbox 与投递记录 | `domain/BridgeInbox.java`、`BridgeDeliveryAttempt.java` 及对应 Mapper |
| 内部服务令牌 | `security/InternalServiceTokenGuard.java` |
| 数据库 | `src/main/resources/db/event-bridge.sql` |
@@ -51,7 +51,8 @@ public class EventBridgeController {
return ApiResponse.success(eventInboxService.receive(envelope));
}
@Operation(summary = "人工补投死信事件")
@Operation(summary = "人工补投死信事件",
description = "仅允许 DEAD 事件转回 RETRY;保留原 eventId、payload 与 payloadHash,必须记录操作人与补投原因")
@PostMapping("/events/{eventId}/replay")
public ApiResponse<Void> replay(
@RequestHeader(value = "X-Internal-Service-Token", required = false) String token,
@@ -3,8 +3,10 @@ package com.baiyue.eventbridge.service;
import com.baiyue.eventbridge.mapper.BridgeInboxMapper;
import org.junit.jupiter.api.Test;
import org.springframework.test.util.ReflectionTestUtils;
import org.apache.ibatis.annotations.Update;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.*;
class EventReplayServiceTest {
@@ -28,6 +30,16 @@ class EventReplayServiceTest {
.isInstanceOf(IllegalStateException.class);
}
@Test
void replayOnlyRequeuesDeadStateAndDoesNotRewriteFrozenEvent() throws Exception {
String sql = String.join(" ", BridgeInboxMapper.class
.getMethod("replayDead", String.class, String.class)
.getAnnotation(Update.class).value()).replaceAll("\\s+", " ");
assertThat(sql).contains("status='RETRY'", "retry_count=0", "status='DEAD'")
.doesNotContain("payload_json=", "payload_hash=");
}
private EventReplayService service() {
EventReplayService service = new EventReplayService();
ReflectionTestUtils.setField(service, "inboxMapper", mapper);