36 lines
2.5 KiB
Plaintext
36 lines
2.5 KiB
Plaintext
$ mvn -pl outbox -am test -Dtest=DualWriteProblemTest
|
|
(NaiveBillingService: save the Invoice, then separately call kafka.send() -- no
|
|
coordinator between the two. spring.kafka.bootstrap-servers points at localhost:19999,
|
|
nothing listening there)
|
|
|
|
2026-10-04T00:52:56.429+05:30 ERROR 5271 --- [outbox] [ main] o.s.k.support.LoggingProducerListener : Exception thrown when sending a message with key='1' and payload='WIDGET-1:1999' to topic invoices-naive:
|
|
|
|
org.apache.kafka.common.errors.TimeoutException: Topic invoices-naive not present in metadata after 2000 ms.
|
|
|
|
Exception thrown synchronously from issueInvoiceTheNaiveWay(): org.springframework.kafka.KafkaException: Send failed
|
|
Invoice count regardless: 1 (was 0). The database write already committed inside saveInvoiceOnly() before this exception was ever thrown -- the exception came from the Kafka call, several lines later, on an already-committed row.
|
|
|
|
2026-10-04T00:52:58.495+05:30 ERROR 5271 --- [outbox] [ main] o.s.k.support.LoggingProducerListener : Exception thrown when sending a message with key='2' and payload='WIDGET-1:2999' to topic invoices-naive:
|
|
|
|
org.apache.kafka.common.errors.TimeoutException: Topic invoices-naive not present in metadata after 2000 ms.
|
|
|
|
Invoice count after the blocked, failed send: 2 (was 1). The row committed before the send was even attempted.
|
|
|
|
[INFO] Tests run: 2, Failures: 0, Errors: 0, Skipped: 0
|
|
|
|
Two real findings here, not one. First, the obvious one: the invoice exists in the
|
|
database in both tests, and Kafka never received either message -- that's the dual-write
|
|
problem, reproduced with nothing faked beyond pointing Kafka at a port with no listener.
|
|
|
|
Second, a more specific one that contradicts the usual "fire-and-forget send() fails
|
|
silently" framing: when the broker can't be reached to fetch topic metadata at all,
|
|
Spring's KafkaTemplate.send() throws synchronously, wrapping the Kafka client's own
|
|
TimeoutException in a KafkaException, even though the method's declared return type is
|
|
a CompletableFuture. The "silent" version of this bug is real, but it is a narrower
|
|
case than total broker unavailability -- it's what happens when the broker is reachable
|
|
and the topic's metadata is known, but the specific produce request times out waiting
|
|
for an acknowledgment afterward. That failure mode surfaces only through the returned
|
|
future or a callback, never as a synchronous exception, and is not reproduced in this
|
|
transcript (it needs a broker that accepts the connection and then stops responding
|
|
mid-request, not one that was never there to begin with).
|