优化
This commit is contained in:
+35
-8
@@ -7,7 +7,6 @@ import com.baiyue.common.event.EventPayloadCanonicalizer;
|
||||
import com.baiyue.common.event.EventPayloadHash;
|
||||
import com.baiyue.common.event.EventTypes;
|
||||
import com.baiyue.common.event.OverseasContainerUnloadedV1;
|
||||
import com.baiyue.common.event.RegionCode;
|
||||
import com.baiyue.lastleg.client.DirectEventClient;
|
||||
import com.baiyue.lastleg.entity.LastlegEventOutbox;
|
||||
import com.baiyue.lastleg.repository.UnloadCompletedOutboxRepository;
|
||||
@@ -23,6 +22,11 @@ import org.springframework.test.util.ReflectionTestUtils;
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import com.baiyue.common.core.outbox.EventDeliveryJournal;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.jdbc.datasource.DriverManagerDataSource;
|
||||
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
@@ -35,11 +39,21 @@ class InboundUnloadCompletedOutboxRelayTest {
|
||||
private ObjectMapper objectMapper;
|
||||
private InboundUnloadCompletedOutboxRelay relay;
|
||||
|
||||
private EventDeliveryJournal journal;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
objectMapper = new ObjectMapper().registerModule(new JavaTimeModule());
|
||||
relay = new InboundUnloadCompletedOutboxRelay();
|
||||
ReflectionTestUtils.setField(relay, "repository", repository);
|
||||
var dataSource = new DriverManagerDataSource("jdbc:h2:mem:" + UUID.randomUUID() + ";MODE=MySQL;DB_CLOSE_DELAY=-1", "sa", "");
|
||||
var jdbc = new JdbcTemplate(dataSource);
|
||||
jdbc.execute("CREATE TABLE event_delivery_attempt(attempt_id VARCHAR(36) PRIMARY KEY,service_name VARCHAR(32) NOT NULL,event_type VARCHAR(96) NOT NULL,entry_id VARCHAR(128) NOT NULL,event_id VARCHAR(128),target_name VARCHAR(64) NOT NULL,started_at TIMESTAMP(3) NOT NULL,finished_at TIMESTAMP(3),duration_ms BIGINT,outcome VARCHAR(24) NOT NULL,error_code VARCHAR(64),next_retry_at TIMESTAMP(3))");
|
||||
journal = new EventDeliveryJournal(jdbc, new DataSourceTransactionManager(dataSource));
|
||||
ReflectionTestUtils.setField(relay, "journal", journal);
|
||||
lenient().when(repository.published(anyLong(), anyString(), any())).thenReturn(1);
|
||||
lenient().when(repository.retry(anyLong(), anyString(), any(), anyString())).thenReturn(1);
|
||||
lenient().when(repository.dead(anyLong(), anyString(), anyInt(), anyString())).thenReturn(1);
|
||||
ReflectionTestUtils.setField(relay, "client", client);
|
||||
ReflectionTestUtils.setField(relay, "objectMapper", objectMapper);
|
||||
ReflectionTestUtils.setField(relay, "internalToken", "internal-token");
|
||||
@@ -52,7 +66,7 @@ class InboundUnloadCompletedOutboxRelayTest {
|
||||
EventEnvelope event = event();
|
||||
LastlegEventOutbox row = row(event);
|
||||
when(repository.pending(eq(50), any(), any())).thenReturn(List.of(row));
|
||||
when(repository.claim(eq(9001L), anyString(), any(), any())).thenReturn(true);
|
||||
when(repository.claim(eq(9001L), anyString(), any())).thenReturn(true);
|
||||
when(repository.claimed(eq(9001L), anyString())).thenReturn(row);
|
||||
when(client.receive(eq("internal-token"), any(EventEnvelope.class)))
|
||||
.thenReturn(ApiResponse.success(DeliveryAck.of(event, DeliveryAck.Outcome.APPLIED)));
|
||||
@@ -68,7 +82,7 @@ class InboundUnloadCompletedOutboxRelayTest {
|
||||
EventEnvelope event = event();
|
||||
LastlegEventOutbox row = row(event);
|
||||
when(repository.pending(eq(50), any(), any())).thenReturn(List.of(row));
|
||||
when(repository.claim(eq(9001L), anyString(), any(), any())).thenReturn(true);
|
||||
when(repository.claim(eq(9001L), anyString(), any())).thenReturn(true);
|
||||
when(repository.claimed(eq(9001L), anyString())).thenReturn(row);
|
||||
when(client.receive(eq("internal-token"), any(EventEnvelope.class)))
|
||||
.thenThrow(new IllegalStateException("consumer unavailable"));
|
||||
@@ -84,7 +98,7 @@ class InboundUnloadCompletedOutboxRelayTest {
|
||||
EventEnvelope event = event();
|
||||
LastlegEventOutbox row = row(event);
|
||||
when(repository.pending(eq(50), any(), any())).thenReturn(List.of(row));
|
||||
when(repository.claim(eq(9001L), anyString(), any(), any())).thenReturn(true);
|
||||
when(repository.claim(eq(9001L), anyString(), any())).thenReturn(true);
|
||||
when(repository.claimed(eq(9001L), anyString())).thenReturn(row);
|
||||
when(client.receive(eq("internal-token"), any(EventEnvelope.class)))
|
||||
.thenReturn(ApiResponse.failure(ResultCode.BAD_REQUEST,
|
||||
@@ -102,7 +116,7 @@ class InboundUnloadCompletedOutboxRelayTest {
|
||||
EventEnvelope event = event();
|
||||
LastlegEventOutbox row = row(event);
|
||||
when(repository.pending(eq(50), any(), any())).thenReturn(List.of(row));
|
||||
when(repository.claim(eq(9001L), anyString(), any(), any())).thenReturn(true);
|
||||
when(repository.claim(eq(9001L), anyString(), any())).thenReturn(true);
|
||||
when(repository.claimed(eq(9001L), anyString())).thenReturn(row);
|
||||
when(client.receive(eq("internal-token"), any(EventEnvelope.class)))
|
||||
.thenReturn(ApiResponse.success(new DeliveryAck(event.eventId(), "sha256:" + "0".repeat(64), DeliveryAck.Outcome.APPLIED)))
|
||||
@@ -118,7 +132,7 @@ class InboundUnloadCompletedOutboxRelayTest {
|
||||
LastlegEventOutbox row = row(event());
|
||||
row.setRetryCount(11);
|
||||
when(repository.pending(eq(50), any(), any())).thenReturn(List.of(row));
|
||||
when(repository.claim(eq(9001L), anyString(), any(), any())).thenReturn(true);
|
||||
when(repository.claim(eq(9001L), anyString(), any())).thenReturn(true);
|
||||
when(repository.claimed(eq(9001L), anyString())).thenReturn(row);
|
||||
when(client.receive(anyString(), any())).thenThrow(new IllegalStateException("consumer unavailable"));
|
||||
relay.relay();
|
||||
@@ -132,7 +146,7 @@ class InboundUnloadCompletedOutboxRelayTest {
|
||||
LastlegEventOutbox row = row(event());
|
||||
row.setRetryCount(12);
|
||||
when(repository.pending(eq(50), any(), any())).thenReturn(List.of(row));
|
||||
when(repository.claim(eq(9001L), anyString(), any(), any())).thenReturn(true);
|
||||
when(repository.claim(eq(9001L), anyString(), any())).thenReturn(true);
|
||||
when(repository.claimed(eq(9001L), anyString())).thenReturn(row);
|
||||
relay.relay();
|
||||
verifyNoInteractions(client);
|
||||
@@ -140,6 +154,19 @@ class InboundUnloadCompletedOutboxRelayTest {
|
||||
verify(repository, never()).retry(anyLong(), anyString(), any(), anyString());
|
||||
}
|
||||
|
||||
@Test
|
||||
void expiredLeaseIsAuditedAndBackedOffWithoutImmediateHttp() throws Exception {
|
||||
var row = row(event());
|
||||
row.setStatus("PROCESSING"); row.setLockedBy("old"); row.setRetryCount(1);
|
||||
journal.begin("old", "lastleg", row.getEventType(), "9001", null, "consumer", LocalDateTime.now().minusMinutes(2), () -> true);
|
||||
when(repository.pending(eq(50), any(), any())).thenReturn(List.of(row));
|
||||
when(repository.expire(eq(9001L), eq("old"), any(), eq(2), any(), anyString())).thenReturn(1);
|
||||
relay.relay();
|
||||
verify(repository).expire(eq(9001L), eq("old"), any(), eq(2), argThat(next -> next.isAfter(LocalDateTime.now())), anyString());
|
||||
verify(repository, never()).claim(anyLong(), anyString(), any());
|
||||
verifyNoInteractions(client);
|
||||
}
|
||||
|
||||
private LastlegEventOutbox row(EventEnvelope event) throws Exception {
|
||||
LastlegEventOutbox row = new LastlegEventOutbox();
|
||||
row.setId(9001L);
|
||||
@@ -153,7 +180,7 @@ class InboundUnloadCompletedOutboxRelayTest {
|
||||
Instant.parse("2026-08-20T03:00:00Z"), Instant.parse("2026-08-20T02:30:00Z"), null));
|
||||
return new EventEnvelope("00000000-0000-4000-8000-000000000009",
|
||||
EventTypes.OVERSEAS_CONTAINER_UNLOADED, 1, Instant.parse("2026-08-20T03:00:01Z"),
|
||||
RegionCode.OVERSEAS, RegionCode.CN, "1", "CONTAINER_BOOKING", "1001", 7L, 1L,
|
||||
"1", "CONTAINER_BOOKING", "1001", 7L, 1L,
|
||||
"trace-12345678", "correlation-12345678", null, payload,
|
||||
EventPayloadHash.sha256(EventPayloadCanonicalizer.canonicalize(payload)));
|
||||
}
|
||||
|
||||
-1
@@ -116,7 +116,6 @@ class InboundUnloadCompletedOutboxServiceTest {
|
||||
Instant.parse("2026-08-24T09:30:00Z"), Instant.parse("2026-08-24T08:00:00Z"), null);
|
||||
EventEnvelope envelope = new EventEnvelope("123e4567-e89b-12d3-a456-426614174000",
|
||||
EventTypes.OVERSEAS_CONTAINER_UNLOADED, 1, Instant.parse("2026-08-24T09:30:01Z"),
|
||||
com.baiyue.common.event.RegionCode.OVERSEAS, com.baiyue.common.event.RegionCode.CN,
|
||||
customerId, "CONTAINER_BOOKING", bookingId, 7, 1L,
|
||||
"123e4567-e89b-12d3-a456-426614174001",
|
||||
EventTypes.OVERSEAS_CONTAINER_UNLOADED + ':' + bookingId, null,
|
||||
|
||||
Reference in New Issue
Block a user