You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: spring-kafka-docs/src/main/asciidoc/kafka.adoc
+1-93
Original file line number
Diff line number
Diff line change
@@ -2310,99 +2310,7 @@ IMPORTANT: The `FilteringBatchMessageListenerAdapter` is ignored if your `@Kafka
2310
2310
[[retrying-deliveries]]
2311
2311
===== Retrying Deliveries
2312
2312
2313
-
If your listener throws an exception, the default behavior is to invoke the <<error-handlers>>, if configured, or logged otherwise.
2314
-
2315
-
NOTE:
2316
-
To retry deliveries, a convenient listener adapter `RetryingMessageListenerAdapter` is provided.
2317
-
2318
-
You can configure it with a `RetryTemplate` and `RecoveryCallback<Void>` - see the https://github.com/spring-projects/spring-retry[spring-retry] project for information about these components.
2319
-
If a recovery callback is not provided, the exception is thrown to the container after retries are exhausted.
2320
-
In that case, the `ErrorHandler` is invoked, if configured, or logged otherwise.
2321
-
2322
-
When you use `@KafkaListener`, you can set the `RetryTemplate` (and optionally `recoveryCallback`) on the container factory.
2323
-
When you do so, the listener is wrapped in the appropriate retrying adapter.
2324
-
2325
-
The contents of the `RetryContext` passed into the `RecoveryCallback` depend on the type of listener.
2326
-
The context always has a `record` attribute, which is the record for which the failure occurred.
2327
-
If your listener is acknowledging or consumer aware, additional `acknowledgment` or `consumer` attributes are available.
2328
-
For convenience, the `RetryingMessageListenerAdapter` provides static constants for these keys.
2329
-
See its https://docs.spring.io/spring-kafka/api/org/springframework/kafka/listener/adapter/AbstractRetryingMessageListenerAdapter.html[Javadoc] for more information.
2330
-
2331
-
A retry adapter is not provided for any of the batch <<message-listeners,message listeners>>, because the framework has no knowledge of where in a batch the failure occurred.
2332
-
If you need retry capabilities when you use a batch listener, we recommend that you use a `RetryTemplate` within the listener itself.
2333
-
2334
-
[[stateful-retry]]
2335
-
===== Stateful Retry
2336
-
2337
-
IMPORTANT: Now that the `SeekToCurrentErrorHandler` can be configured with a `BackOff` and has the ability to retry only certain exceptions (since version 2.3), the use of stateful retry, via the listener adapter retry configuration, is no longer necessary.
2338
-
You can provide the same functionality with appropriate configuration of the error handler and remove all retry configuration from the listener adapter.
2339
-
See <<seek-to-current>> for more information.
2340
-
2341
-
You should understand that the retry discussed in the <<retrying-deliveries,preceding section>> suspends the consumer thread (if a `BackOffPolicy` is used).
2342
-
There are no calls to `Consumer.poll()` during the retries.
2343
-
Kafka has two properties to determine consumer health.
2344
-
The `session.timeout.ms` is used to determine if the consumer is active.
2345
-
Since `kafka-clients` version `0.10.1.0`, heartbeats are sent on a background thread, so a slow consumer no longer affects that.
2346
-
`max.poll.interval.ms` (default: five minutes) is used to determine if a consumer appears to be hung (taking too long to process records from the last poll).
2347
-
If the time between `poll()` calls exceeds this, the broker revokes the assigned partitions and performs a rebalance.
2348
-
For lengthy retry sequences, with back off, this can easily happen.
2349
-
2350
-
Since version 2.1.3, you can avoid this problem by using stateful retry in conjunction with a `SeekToCurrentErrorHandler`.
2351
-
In this case, each delivery attempt throws the exception back to the container, the error handler re-seeks the unprocessed offsets, and the same message is redelivered by the next `poll()`.
2352
-
This avoids the problem of exceeding the `max.poll.interval.ms` property (as long as an individual delay between attempts does not exceed it).
2353
-
So, when you use an `ExponentialBackOffPolicy`, you must ensure that the `maxInterval` is less than the `max.poll.interval.ms` property.
2354
-
To enable stateful retry, you can use the `RetryingMessageListenerAdapter` constructor that takes a `stateful` `boolean` argument (set it to `true`).
2355
-
When you configure the listener container factory (for `@KafkaListener`), set the factory's `statefulRetry` property to `true`.
2356
-
2357
-
IMPORTANT: Version 2.2 added recovery to the `SeekToCurrentErrorHandler`, such as sending a failed record to a dead-letter topic.
2358
-
When using stateful retry, you must perform the recovery in the retry `RecoveryCallback` and NOT in the error handler.
2359
-
Otherwise, if the recovery is done in the error handler, the retry template's state will never be cleared.
2360
-
Also, you must ensure that the `maxFailures` in the `SeekToCurrentErrorHandler` must be at least as many as configured in the retry policy, again to ensure that the retries are exhausted and the state cleared.
2361
-
Here is an example for retry configuration when used with a `SeekToCurrentErrorHandler` where `factory` is the `ConcurrentKafkaListenerContainerFactory`.
2362
-
2363
-
====
2364
-
[source, java]
2365
-
----
2366
-
@Autowired
2367
-
DeadLetterPublishingRecoverer recoverer;
2368
-
2369
-
...
2370
-
factory.setRetryTemplate(new RetryTemplate()); // 3 retries by default
return new SeekToCurrentErrorHandler(new FixedBackOff(0L, 3L)); // at least 3
2382
-
}
2383
-
----
2384
-
====
2385
-
2386
-
However, see the note at the beginning of this section; you can avoid using the `RetryTemplate` altogether.
2387
-
2388
-
IMPORTANT: If the recoverer fails (throws an exception), the failed record will be included in the seeks.
2389
-
Starting with version 2.5.5, if the recoverer fails, the `BackOff` will be reset by default and redeliveries will again go through the back offs before recovery is attempted again.
2390
-
With earlier versions, the `BackOff` was not reset and recovery was re-attempted on the next failure.
2391
-
To revert to the previous behavior, set the error handler's `resetStateOnRecoveryFailure` to `false`.
2392
-
2393
-
Starting with version 2.6, you can now provide the error handler with a `BiFunction<ConsumerRecord<?, ?>, Exception, BackOff>` to determine the `BackOff` to use, based on the failed record and/or the exception:
If the function returns `null`, the handler's default `BackOff` will be used.
2403
-
2404
-
Starting with version 2.6.3, set `resetStateOnExceptionChange` to `true` and the retry sequence will be restarted (including the selection of a new `BackOff`, if so configured) if the exception type changes between failures.
2405
-
By default, the exception type is not considered.
2313
+
See the `SeekToCurrentErrorHandler` in <<annotation-error-handling>>.
Copy file name to clipboardExpand all lines: spring-kafka/src/test/java/org/springframework/kafka/listener/adapter/RetryingMessageListenerAdapterTests.java
0 commit comments