|
116 | 116 | * {@code group.share.record.lock.partition.limit}. By limiting the duration of the acquisition lock and automatically
|
117 | 117 | * releasing the locks, the broker ensures delivery progresses even in the presence of consumer failures.
|
118 | 118 | * <p>
|
119 |
| - * The consumer can choose to use implicit or explicit acknowledgement of the records it processes. |
120 |
| - * <p>If the application calls {@link #acknowledge(ConsumerRecord, AcknowledgeType)} for any record in the batch, |
121 |
| - * it is using <em>explicit acknowledgement</em>. In this case: |
122 |
| - * <ul> |
123 |
| - * <li>The application calls {@link #commitSync()} or {@link #commitAsync()} which commits the acknowledgements to Kafka. |
124 |
| - * If any records in the batch were not acknowledged, they remain acquired and will be presented to the application |
125 |
| - * in response to a future poll.</li> |
126 |
| - * <li>The application calls {@link #poll(Duration)} without committing first, which commits the acknowledgements to |
127 |
| - * Kafka asynchronously. In this case, no exception is thrown by a failure to commit the acknowledgement. |
128 |
| - * If any records in the batch were not acknowledged, they remain acquired and will be presented to the application |
129 |
| - * in response to a future poll.</li> |
130 |
| - * <li>The application calls {@link #close()} which attempts to commit any pending acknowledgements and |
131 |
| - * releases any remaining acquired records.</li> |
132 |
| - * </ul> |
133 |
| - * If the application does not call {@link #acknowledge(ConsumerRecord, AcknowledgeType)} for any record in the batch, |
134 |
| - * it is using <em>implicit acknowledgement</em>. In this case: |
| 119 | + * The consumer can choose to use implicit or explicit acknowledgement of the records it processes by configuring the |
| 120 | + * consumer {@code share.acknowledgement.mode} property. |
| 121 | + * <p> |
| 122 | + * If the application sets the property to "implicit" or does not set it at all, then the consumer is using |
| 123 | + * <em>implicit acknowledgement</em>. In this mode, the application acknowledges delivery by: |
135 | 124 | * <ul>
|
136 |
| - * <li>The application calls {@link #commitSync()} or {@link #commitAsync()} which implicitly acknowledges all of |
137 |
| - * the delivered records as processed successfully and commits the acknowledgements to Kafka.</li> |
138 |
| - * <li>The application calls {@link #poll(Duration)} without committing, which also implicitly acknowledges all of |
| 125 | + * <li>Calling {@link #poll(Duration)} without committing, which also implicitly acknowledges all |
139 | 126 | * the delivered records and commits the acknowledgements to Kafka asynchronously. In this case, no exception is
|
140 | 127 | * thrown by a failure to commit the acknowledgements.</li>
|
141 |
| - * <li>The application calls {@link #close()} which releases any acquired records without acknowledgement.</li> |
| 128 | + * <li>Calling {@link #commitSync()} or {@link #commitAsync()} which implicitly acknowledges all |
| 129 | + * the delivered records as processed successfully and commits the acknowledgements to Kafka.</li> |
| 130 | + * <li>Calling {@link #close()} which releases any acquired records without acknowledgement.</li> |
| 131 | + * </ul> |
| 132 | + * If the application sets the property to "explicit", then the consumer is using <em>explicit acknowledgment</em>. |
| 133 | + * The application must acknowledge all records returned from {@link #poll(Duration)} using |
| 134 | + * {@link #acknowledge(ConsumerRecord, AcknowledgeType)} before its next call to {@link #poll(Duration)}. |
| 135 | + * If the application calls {@link #poll(Duration)} without having acknowledged all records, an |
| 136 | + * {@link IllegalStateException} is thrown. The remaining unacknowledged records can still be acknowledged. |
| 137 | + * In this mode, the application acknowledges delivery by: |
| 138 | + * <ul> |
| 139 | + * <li>Calling {@link #poll(Duration)} after it has acknowledged all records, which commits the acknowledgements |
| 140 | + * to Kafka asynchronously. In this case, no exception is thrown by a failure to commit the acknowledgements.</li> |
| 141 | + * <li>Calling {@link #commitSync()} or {@link #commitAsync()} which commits any pending |
| 142 | + * acknowledgements to Kafka.</li> |
| 143 | + * <li>Calling {@link #close()} which attempts to commit any pending acknowledgements and releases |
| 144 | + * any remaining acquired records.</li> |
142 | 145 | * </ul>
|
143 |
| - * <p>The consumer can optionally use the {@code internal.share.acknowledgement.mode} configuration property to choose |
144 |
| - * between implicit and explicit acknowledgement, specifying <code>"implicit"</code> or <code>"explicit"</code> as required. |
145 |
| - * <p> |
146 | 146 | * The consumer guarantees that the records returned in the {@code ConsumerRecords} object for a specific topic-partition
|
147 | 147 | * are in order of increasing offset. For each topic-partition, Kafka guarantees that acknowledgements for the records
|
148 | 148 | * in a batch are performed atomically. This makes error handling significantly more straightforward because there can be
|
|
195 | 195 | *
|
196 | 196 | * <h4>Per-record acknowledgement (explicit acknowledgement)</h4>
|
197 | 197 | * This example demonstrates using different acknowledgement types depending on the outcome of processing the records.
|
| 198 | + * Here the {@code share.acknowledgement.mode} property is set to "explicit" so the consumer must explicitly acknowledge each record. |
198 | 199 | * <pre>
|
199 | 200 | * Properties props = new Properties();
|
200 | 201 | * props.setProperty("bootstrap.servers", "localhost:9092");
|
201 | 202 | * props.setProperty("group.id", "test");
|
202 | 203 | * props.setProperty("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
|
203 | 204 | * props.setProperty("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
|
| 205 | + * props.setProperty("share.acknowledgement.mode", "explicit"); |
204 | 206 | * KafkaShareConsumer<String, String> consumer = new KafkaShareConsumer<>(props);
|
205 | 207 | * consumer.subscribe(Arrays.asList("foo"));
|
206 | 208 | * while (true) {
|
|
227 | 229 | * It is only once {@link #commitSync()} is called that the acknowledgements are committed by sending the new state
|
228 | 230 | * information to Kafka.
|
229 | 231 | *
|
230 |
| - * <h4>Per-record acknowledgement, ending processing of the batch on an error (explicit acknowledgement)</h4> |
231 |
| - * This example demonstrates ending processing of a batch of records on the first error. |
232 |
| - * <pre> |
233 |
| - * Properties props = new Properties(); |
234 |
| - * props.setProperty("bootstrap.servers", "localhost:9092"); |
235 |
| - * props.setProperty("group.id", "test"); |
236 |
| - * props.setProperty("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer"); |
237 |
| - * props.setProperty("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer"); |
238 |
| - * KafkaShareConsumer<String, String> consumer = new KafkaShareConsumer<>(props); |
239 |
| - * consumer.subscribe(Arrays.asList("foo")); |
240 |
| - * while (true) { |
241 |
| - * ConsumerRecords<String, String> records = consumer.poll(Duration.ofMillis(100)); |
242 |
| - * for (ConsumerRecord<String, String> record : records) { |
243 |
| - * try { |
244 |
| - * doProcessing(record); |
245 |
| - * consumer.acknowledge(record, AcknowledgeType.ACCEPT); |
246 |
| - * } catch (Exception e) { |
247 |
| - * consumer.acknowledge(record, AcknowledgeType.REJECT); |
248 |
| - * break; |
249 |
| - * } |
250 |
| - * } |
251 |
| - * consumer.commitSync(); |
252 |
| - * } |
253 |
| - * </pre> |
254 |
| - * There are the following cases in this example: |
255 |
| - * <ol> |
256 |
| - * <li>The batch contains no records, in which case the application just polls again. The call to {@link #commitSync()} |
257 |
| - * just does nothing because the batch was empty.</li> |
258 |
| - * <li>All of the records in the batch are processed successfully. The calls to {@link #acknowledge(ConsumerRecord, AcknowledgeType)} |
259 |
| - * specifying {@code AcknowledgeType.ACCEPT} mark all records in the batch as successfully processed.</li> |
260 |
| - * <li>One of the records encounters an exception. The call to {@link #acknowledge(ConsumerRecord, AcknowledgeType)} specifying |
261 |
| - * {@code AcknowledgeType.REJECT} rejects that record. Earlier records in the batch have already been marked as successfully |
262 |
| - * processed. The call to {@link #commitSync()} commits the acknowledgements, but the records after the failed record |
263 |
| - * remain acquired as part of the same delivery attempt and will be presented to the application in response to another poll.</li> |
264 |
| - * </ol> |
265 |
| - * |
266 | 232 | * <h3>Reading Transactional Records</h3>
|
267 | 233 | * The way that share groups handle transactional records is controlled by the {@code group.share.isolation.level}</code>
|
268 | 234 | * configuration property. In a share group, the isolation level applies to the entire share group, not just individual
|
|
0 commit comments