feat: productionize raw history ingestion

This commit is contained in:
lingniu
2026-06-30 23:21:58 +08:00
parent 3cc7ac9669
commit cbba617801
100 changed files with 2995 additions and 1697 deletions

View File

@@ -43,7 +43,7 @@ class Gb32960ChannelHandlerAckBoundaryTest {
dispatch.awaitPublishCount(1);
dispatch.completeDurability();
ByteBuf ack = readOutboundAfterRunningTasks(channel);
ByteBuf ack = awaitOutbound(channel);
assertThat(ack).isNotNull();
assertThat(ack.getUnsignedByte(2)).isEqualTo((short) 0x02);
assertThat(ack.getUnsignedByte(3)).isEqualTo((short) 0x01);
@@ -85,8 +85,8 @@ class Gb32960ChannelHandlerAckBoundaryTest {
dispatch.completeDurability(0);
ByteBuf firstAck = readOutboundAfterRunningTasks(channel);
ByteBuf secondAck = readOutboundAfterRunningTasks(channel);
ByteBuf firstAck = awaitOutbound(channel);
ByteBuf secondAck = awaitOutbound(channel);
assertThat(firstAck).isNotNull();
assertThat(secondAck).isNotNull();
assertThat(firstAck.getUnsignedByte(2)).isEqualTo((short) 0x02);
@@ -97,42 +97,6 @@ class Gb32960ChannelHandlerAckBoundaryTest {
}
}
@Test
void decodeFailureIsArchivedWithParseErrorMetadata() {
try (DispatchHarness dispatch = new DispatchHarness()) {
EmbeddedChannel channel = new EmbeddedChannel(handlerWith(dispatch.dispatcher()));
byte[] malformed = new byte[]{0x23, 0x23, 0x02};
assertThat(channel.writeInbound(malformed)).isFalse();
dispatch.awaitPublishCount(1);
VehicleEvent event = dispatch.event(0);
assertThat(event).isInstanceOf(VehicleEvent.RawArchive.class);
VehicleEvent.RawArchive raw = (VehicleEvent.RawArchive) event;
assertThat(raw.source()).isEqualTo(com.lingniu.ingest.api.ProtocolId.GB32960);
assertThat(raw.command()).isZero();
assertThat(raw.rawBytes()).containsExactly(malformed);
assertThat(raw.metadata())
.containsEntry("vin", "unknown")
.containsEntry("parseError", "true")
.containsKey("parseErrorMessage");
channel.finishAndReleaseAll();
}
}
private static ByteBuf readOutboundAfterRunningTasks(EmbeddedChannel channel) {
long deadline = System.currentTimeMillis() + 3000;
while (System.currentTimeMillis() < deadline) {
channel.runPendingTasks();
ByteBuf outbound = channel.readOutbound();
if (outbound != null) {
return outbound;
}
Thread.onSpinWait();
}
return null;
}
private static Gb32960ChannelHandler handlerWith(Dispatcher dispatcher) {
return new Gb32960ChannelHandler(
decoder(),
@@ -174,6 +138,19 @@ class Gb32960ChannelHandlerAckBoundaryTest {
return out.toByteArray();
}
private static ByteBuf awaitOutbound(EmbeddedChannel channel) {
long deadline = System.currentTimeMillis() + 3000;
while (System.currentTimeMillis() < deadline) {
channel.runPendingTasks();
ByteBuf outbound = channel.readOutbound();
if (outbound != null) {
return outbound;
}
Thread.onSpinWait();
}
return null;
}
private static final class DispatchHarness implements AutoCloseable {
private final ControlledSink sink = new ControlledSink();
private final DisruptorEventBus eventBus = new DisruptorEventBus(1024, "blocking", List.of(sink));
@@ -214,12 +191,6 @@ class Gb32960ChannelHandlerAckBoundaryTest {
throw new AssertionError("expected " + count + " sink publishes, actual=" + sink.futures.size());
}
VehicleEvent event(int index) {
synchronized (sink.futures) {
return sink.events.get(index);
}
}
@Override
public void close() {
batchExecutor.close();
@@ -229,7 +200,6 @@ class Gb32960ChannelHandlerAckBoundaryTest {
private static final class ControlledSink implements EventSink {
private final List<CompletableFuture<Void>> futures = new ArrayList<>();
private final List<VehicleEvent> events = new ArrayList<>();
@Override
public String name() {
@@ -240,7 +210,6 @@ class Gb32960ChannelHandlerAckBoundaryTest {
public CompletableFuture<Void> publish(VehicleEvent event) {
CompletableFuture<Void> future = new CompletableFuture<>();
synchronized (futures) {
events.add(event);
futures.add(future);
}
return future;