/** * Get a list of batches which have been sitting in the accumulator too long and need to be expired. */ public List<ProducerBatch> expiredBatches(long now) { List<ProducerBatch> expiredBatches = new ArrayList<>(); for (Map.Entry<TopicPartition, Deque<ProducerBatch>> entry : this.batches.entrySet()) { // expire the batches in the order of sending Deque<ProducerBatch> deque = entry.getValue(); synchronized (deque) { while (!deque.isEmpty()) { ProducerBatch batch = deque.getFirst(); if (batch.hasReachedDeliveryTimeout(deliveryTimeoutMs, now)) { deque.poll(); batch.abortRecordAppends(); expiredBatches.add(batch); } else { maybeUpdateNextBatchExpiryTime(batch); break; } } } } return expiredBatches; }
while (iter.hasNext()) { ProducerBatch batch = iter.next(); if (batch.hasReachedDeliveryTimeout(accumulator.getDeliveryTimeoutMs(), now)) { iter.remove();
/** * A {@link ProducerBatch} configured using a timestamp preceding its create time is interpreted correctly * as not expired by {@link ProducerBatch#hasReachedDeliveryTimeout(long, long)}. */ @Test public void testBatchExpiration() { long deliveryTimeoutMs = 10240; ProducerBatch batch = new ProducerBatch(new TopicPartition("topic", 1), memoryRecordsBuilder, now); // Set `now` to 2ms before the create time. assertFalse(batch.hasReachedDeliveryTimeout(deliveryTimeoutMs, now - 2)); // Set `now` to deliveryTimeoutMs. assertTrue(batch.hasReachedDeliveryTimeout(deliveryTimeoutMs, now + deliveryTimeoutMs)); }
/** * We can retry a send if the error is transient and the number of attempts taken is fewer than the maximum allowed. * We can also retry OutOfOrderSequence exceptions for future batches, since if the first batch has failed, the * future batches are certain to fail with an OutOfOrderSequence exception. */ private boolean canRetry(ProducerBatch batch, ProduceResponse.PartitionResponse response, long now) { return !batch.hasReachedDeliveryTimeout(accumulator.getDeliveryTimeoutMs(), now) && batch.attempts() < this.retries && !batch.isDone() && ((response.error.exception() instanceof RetriableException) || (transactionManager != null && transactionManager.canRetry(response, batch))); }
/** * A {@link ProducerBatch} configured using a timestamp preceding its create time is interpreted correctly * * as not expired by {@link ProducerBatch#hasReachedDeliveryTimeout(long, long)}. */ @Test public void testBatchExpirationAfterReenqueue() { ProducerBatch batch = new ProducerBatch(new TopicPartition("topic", 1), memoryRecordsBuilder, now); // Set batch.retry = true batch.reenqueued(now); // Set `now` to 2ms before the create time. assertFalse(batch.hasReachedDeliveryTimeout(10240, now - 2L)); }