fix: delay jt808 ack until durable dispatch
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
This commit is contained in:
@@ -29,6 +29,7 @@ import com.lingniu.ingest.protocol.jt808.model.Jt808MessageId;
|
||||
import com.lingniu.ingest.protocol.jt808.session.Jt808ChannelRegistry;
|
||||
import com.lingniu.ingest.protocol.jt808.session.Jt808PendingRequests;
|
||||
import com.lingniu.ingest.session.InMemorySessionStore;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.embedded.EmbeddedChannel;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
@@ -49,7 +50,7 @@ class Jt808ChannelHandlerTest {
|
||||
InMemoryVehicleIdentityService identity = new InMemoryVehicleIdentityService();
|
||||
identity.bind(new VehicleIdentityBinding(
|
||||
ProtocolId.JT808, "LNVIN000000000808", "123456789012", "DEV808", "B80808"));
|
||||
DisruptorEventBus eventBus = new DisruptorEventBus(1024, "blocking", List.of());
|
||||
DisruptorEventBus eventBus = new DisruptorEventBus(1024, "blocking", List.of(new ImmediateKafkaSink()));
|
||||
AsyncBatchExecutor batchExecutor = new AsyncBatchExecutor(eventBus::publish);
|
||||
Dispatcher dispatcher = new Dispatcher(
|
||||
new HandlerRegistry(),
|
||||
@@ -88,7 +89,7 @@ class Jt808ChannelHandlerTest {
|
||||
void unresolvedRegisterDoesNotBindUnknownVinToExternalIdentifiers() {
|
||||
InMemorySessionStore sessions = new InMemorySessionStore();
|
||||
InMemoryVehicleIdentityService identity = new InMemoryVehicleIdentityService();
|
||||
DisruptorEventBus eventBus = new DisruptorEventBus(1024, "blocking", List.of());
|
||||
DisruptorEventBus eventBus = new DisruptorEventBus(1024, "blocking", List.of(new ImmediateKafkaSink()));
|
||||
AsyncBatchExecutor batchExecutor = new AsyncBatchExecutor(eventBus::publish);
|
||||
Dispatcher dispatcher = new Dispatcher(
|
||||
new HandlerRegistry(),
|
||||
@@ -129,7 +130,7 @@ class Jt808ChannelHandlerTest {
|
||||
InMemoryVehicleIdentityService identity = new InMemoryVehicleIdentityService();
|
||||
identity.bind(new VehicleIdentityBinding(
|
||||
ProtocolId.JT808, "LNVIN000000AUTH01", "123456789012", "123456789012345", ""));
|
||||
DisruptorEventBus eventBus = new DisruptorEventBus(1024, "blocking", List.of());
|
||||
DisruptorEventBus eventBus = new DisruptorEventBus(1024, "blocking", List.of(new ImmediateKafkaSink()));
|
||||
AsyncBatchExecutor batchExecutor = new AsyncBatchExecutor(eventBus::publish);
|
||||
Dispatcher dispatcher = new Dispatcher(
|
||||
new HandlerRegistry(),
|
||||
@@ -161,10 +162,48 @@ class Jt808ChannelHandlerTest {
|
||||
eventBus.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
void registerAckWaitsForDispatchDurability() {
|
||||
ControlledSink sink = new ControlledSink();
|
||||
DisruptorEventBus eventBus = new DisruptorEventBus(1024, "blocking", List.of(sink));
|
||||
AsyncBatchExecutor batchExecutor = new AsyncBatchExecutor(eventBus::publish);
|
||||
Dispatcher dispatcher = new Dispatcher(
|
||||
new HandlerRegistry(),
|
||||
new InterceptorChain(List.of()),
|
||||
new HandlerInvoker(),
|
||||
eventBus,
|
||||
batchExecutor);
|
||||
Jt808ChannelHandler handler = new Jt808ChannelHandler(
|
||||
new Jt808MessageDecoder(new BodyParserRegistry(List.of(new RegisterBodyParser()))),
|
||||
dispatcher,
|
||||
new InMemorySessionStore(),
|
||||
new InMemoryVehicleIdentityService(),
|
||||
new Jt808ChannelRegistry(),
|
||||
new Jt808PendingRequests());
|
||||
EmbeddedChannel channel = new EmbeddedChannel(handler);
|
||||
|
||||
channel.writeInbound(buildFrame(
|
||||
Jt808MessageId.TERMINAL_REGISTER,
|
||||
"123456789012",
|
||||
1,
|
||||
buildRegisterBody("DEV808", "B80808")));
|
||||
|
||||
assertThat((Object) channel.readOutbound()).isNull();
|
||||
sink.awaitPublishCount(1);
|
||||
sink.future(0).complete(null);
|
||||
|
||||
ByteBuf ack = readOutboundAfterRunningTasks(channel);
|
||||
assertThat(ack).isNotNull();
|
||||
ack.release();
|
||||
|
||||
batchExecutor.close();
|
||||
eventBus.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
void inactiveChannelRemovesSessionStoreEntry() {
|
||||
InMemorySessionStore sessions = new InMemorySessionStore();
|
||||
DisruptorEventBus eventBus = new DisruptorEventBus(1024, "blocking", List.of());
|
||||
DisruptorEventBus eventBus = new DisruptorEventBus(1024, "blocking", List.of(new ImmediateKafkaSink()));
|
||||
AsyncBatchExecutor batchExecutor = new AsyncBatchExecutor(eventBus::publish);
|
||||
Dispatcher dispatcher = new Dispatcher(
|
||||
new HandlerRegistry(),
|
||||
@@ -596,6 +635,62 @@ class Jt808ChannelHandlerTest {
|
||||
os.write((int) (v & 0xFF));
|
||||
}
|
||||
|
||||
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 final class ControlledSink implements EventSink {
|
||||
private final List<CompletableFuture<Void>> futures = new CopyOnWriteArrayList<>();
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return "kafka";
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> publish(VehicleEvent event) {
|
||||
CompletableFuture<Void> future = new CompletableFuture<>();
|
||||
futures.add(future);
|
||||
return future;
|
||||
}
|
||||
|
||||
private CompletableFuture<Void> future(int index) {
|
||||
return futures.get(index);
|
||||
}
|
||||
|
||||
private void awaitPublishCount(int expected) {
|
||||
long deadline = System.currentTimeMillis() + 3000;
|
||||
while (System.currentTimeMillis() < deadline) {
|
||||
if (futures.size() >= expected) {
|
||||
return;
|
||||
}
|
||||
Thread.onSpinWait();
|
||||
}
|
||||
throw new AssertionError("expected " + expected + " sink publishes, actual=" + futures.size());
|
||||
}
|
||||
}
|
||||
|
||||
private static final class ImmediateKafkaSink implements EventSink {
|
||||
@Override
|
||||
public String name() {
|
||||
return "kafka";
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> publish(VehicleEvent event) {
|
||||
return CompletableFuture.completedFuture(null);
|
||||
}
|
||||
}
|
||||
|
||||
private static final class RecordingSink implements EventSink {
|
||||
private final List<VehicleEvent> events = new CopyOnWriteArrayList<>();
|
||||
private final CountDownLatch latch;
|
||||
@@ -606,7 +701,7 @@ class Jt808ChannelHandlerTest {
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
return "recording";
|
||||
return "kafka";
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
Reference in New Issue
Block a user