synchronized boolean isSendToPartitionAllowed(TopicPartition tp) { if (hasFatalError()) return false; return !isTransactional() || partitionsInTransaction.contains(tp); }
} else if (transactionManager.hasUnresolvedSequences() && !transactionManager.hasFatalError()) { transactionManager.transitionToFatalError( new KafkaException("The client hasn't received acknowledgment for " + if (transactionManager.hasFatalError() || !transactionManager.hasProducerId()) { RuntimeException lastError = transactionManager.lastError(); if (lastError != null)
@Test public void testIsSendToPartitionAllowedWithPendingPartitionAfterFatalError() { final long pid = 13131L; final short epoch = 1; doInitTransactions(pid, epoch); transactionManager.beginTransaction(); transactionManager.maybeAddPartitionToTransaction(tp0); transactionManager.transitionToFatalError(new KafkaException()); assertFalse(transactionManager.isSendToPartitionAllowed(tp0)); assertTrue(transactionManager.hasFatalError()); }
@Test public void testUnsupportedVersionInProduceRequest() throws Exception { final long producerId = 343434L; TransactionManager transactionManager = new TransactionManager(); setupWithTransactionState(transactionManager); prepareAndReceiveInitProducerId(producerId, Errors.NONE); assertTrue(transactionManager.hasProducerId()); Future<RecordMetadata> future = accumulator.append(tp0, time.milliseconds(), "key".getBytes(), "value".getBytes(), null, null, MAX_BLOCK_TIMEOUT).future; client.prepareUnsupportedVersionResponse(new MockClient.RequestMatcher() { @Override public boolean matches(AbstractRequest body) { return body instanceof ProduceRequest && ((ProduceRequest) body).hasIdempotentRecords(); } }); sender.run(time.milliseconds()); assertFutureFailure(future, UnsupportedVersionException.class); // unsupported version errors are fatal, so we should continue seeing it on future sends assertTrue(transactionManager.hasFatalError()); assertSendFailure(UnsupportedVersionException.class); }
@Test public void testClusterAuthorizationExceptionInProduceRequest() throws Exception { final long producerId = 343434L; TransactionManager transactionManager = new TransactionManager(); setupWithTransactionState(transactionManager); prepareAndReceiveInitProducerId(producerId, Errors.NONE); assertTrue(transactionManager.hasProducerId()); // cluster authorization is a fatal error for the producer Future<RecordMetadata> future = accumulator.append(tp0, time.milliseconds(), "key".getBytes(), "value".getBytes(), null, null, MAX_BLOCK_TIMEOUT).future; client.prepareResponse(new MockClient.RequestMatcher() { @Override public boolean matches(AbstractRequest body) { return body instanceof ProduceRequest && ((ProduceRequest) body).hasIdempotentRecords(); } }, produceResponse(tp0, -1, Errors.CLUSTER_AUTHORIZATION_FAILED, 0)); sender.run(time.milliseconds()); assertFutureFailure(future, ClusterAuthorizationException.class); // cluster authorization errors are fatal, so we should continue seeing it on future sends assertTrue(transactionManager.hasFatalError()); assertSendFailure(ClusterAuthorizationException.class); }
@Test public void shouldFailAbortIfAddOffsetsFailsWithFatalError() { final long pid = 13131L; final short epoch = 1; doInitTransactions(pid, epoch); transactionManager.beginTransaction(); Map<TopicPartition, OffsetAndMetadata> offsets = new HashMap<>(); offsets.put(tp1, new OffsetAndMetadata(1)); final String consumerGroupId = "myconsumergroup"; transactionManager.sendOffsetsToTransaction(offsets, consumerGroupId); TransactionalRequestResult abortResult = transactionManager.beginAbort(); prepareAddOffsetsToTxnResponse(Errors.UNKNOWN_SERVER_ERROR, consumerGroupId, pid, epoch); sender.run(time.milliseconds()); // Send AddOffsetsToTxnRequest assertFalse(abortResult.isCompleted()); sender.run(time.milliseconds()); assertTrue(abortResult.isCompleted()); assertFalse(abortResult.isSuccessful()); assertTrue(transactionManager.hasFatalError()); }
@Test public void testIsSendToPartitionAllowedWithInFlightPartitionAddAfterFatalError() { final long pid = 13131L; final short epoch = 1; doInitTransactions(pid, epoch); transactionManager.beginTransaction(); transactionManager.maybeAddPartitionToTransaction(tp0); // Send the AddPartitionsToTxn request and leave it in-flight sender.run(time.milliseconds()); transactionManager.transitionToFatalError(new KafkaException()); assertFalse(transactionManager.isSendToPartitionAllowed(tp0)); assertTrue(transactionManager.hasFatalError()); }
@Test public void testIsSendToPartitionAllowedWithAddedPartitionAfterFatalError() { final long pid = 13131L; final short epoch = 1; doInitTransactions(pid, epoch); transactionManager.beginTransaction(); transactionManager.maybeAddPartitionToTransaction(tp0); prepareAddPartitionsToTxnResponse(Errors.NONE, tp0, epoch, pid); sender.run(time.milliseconds()); assertFalse(transactionManager.hasPartitionsToAdd()); transactionManager.transitionToFatalError(new KafkaException()); assertFalse(transactionManager.isSendToPartitionAllowed(tp0)); assertTrue(transactionManager.hasFatalError()); }
@Test public void testUnsupportedFindCoordinator() { transactionManager.initializeTransactions(); client.prepareUnsupportedVersionResponse(body -> { FindCoordinatorRequest findCoordinatorRequest = (FindCoordinatorRequest) body; assertEquals(findCoordinatorRequest.coordinatorType(), CoordinatorType.TRANSACTION); assertEquals(findCoordinatorRequest.coordinatorKey(), transactionalId); return true; }); sender.run(time.milliseconds()); // InitProducerRequest is queued sender.run(time.milliseconds()); // FindCoordinator is queued after peeking InitProducerRequest assertTrue(transactionManager.hasFatalError()); assertTrue(transactionManager.lastError() instanceof UnsupportedVersionException); }
assertTrue(transactionManager.hasFatalError()); assertFutureFailure(future1, ClusterAuthorizationException.class);
assertTrue(transactionManager.hasFatalError()); assertFalse(transactionManager.hasOngoingTransaction());
@Test public void testUnsupportedInitTransactions() { transactionManager.initializeTransactions(); prepareFindCoordinatorResponse(Errors.NONE, false, CoordinatorType.TRANSACTION, transactionalId); sender.run(time.milliseconds()); // InitProducerRequest is queued sender.run(time.milliseconds()); // FindCoordinator is queued after peeking InitProducerRequest assertFalse(transactionManager.hasError()); assertNotNull(transactionManager.coordinator(CoordinatorType.TRANSACTION)); client.prepareUnsupportedVersionResponse(body -> { InitProducerIdRequest initProducerIdRequest = (InitProducerIdRequest) body; assertEquals(initProducerIdRequest.transactionalId(), transactionalId); assertEquals(initProducerIdRequest.transactionTimeoutMs(), transactionTimeoutMs); return true; }); sender.run(time.milliseconds()); // InitProducerRequest is dequeued assertTrue(transactionManager.hasFatalError()); assertTrue(transactionManager.lastError() instanceof UnsupportedVersionException); }