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
Add comprehensive acknowledgment support for Kafka share consumers
* Add comprehensive acknowledgment support for Kafka share consumers
Implement explicit and implicit acknowledgment modes for share consumer
containers, enabling fine-grained control over record processing outcomes
with ACCEPT, RELEASE, and REJECT acknowledgment types.
- Add ShareAcknowledgment interface with ACCEPT/RELEASE/REJECT support
- Add ShareAcknowledgmentException for acknowledgment failures
- Implement ShareAcknowledgmentMode enum (IMPLICIT/EXPLICIT) in ContainerProperties
- Add poll-level acknowledgment constraints in explicit mode
- Add ShareConsumerAwareMessageListener for ShareConsumer access
- Add AcknowledgingShareConsumerAwareMessageListener for explicit acknowledgment
- Add ShareRecordMessagingMessageListenerAdapter for KafkaListener integration
- Use non-polymorphic onShareRecord method names to avoid regression issues
with existing listener infrastructure and maintain clear API separation
- Enhanced ShareKafkaMessageListenerContainer with acknowledgment tracking
- Automatic error handling with REJECT acknowledgment on exceptions
- Poll blocking in explicit mode until all records acknowledged
- Support for mixed acknowledgment patterns within single poll
- Auto-detection of ShareKafkaListenerContainerFactory for share consumer endpoints
- Validation preventing batch listeners with share consumers
- Factory-level and container-level acknowledgment mode configuration
- Message converter extensions for ShareAcknowledgment parameter injection
- Comprehensive integration tests covering all acknowledgment scenarios
- Constraint tests validating poll-level acknowledgment requirements
- Unit tests for container behavior and listener dispatching
- Updated documentation with acknowledgment examples
- Implicit: Records auto-acknowledged as ACCEPT on success, REJECT on error
- Explicit: Application must manually acknowledge each record before next poll
- Explicit mode blocks subsequent polls until all records acknowledged
- Prevents message loss and ensures proper acknowledgment ordering
- Concurrent acknowledgment attempts properly handled with IllegalStateException
- Processing exceptions trigger automatic REJECT acknowledgment
- Acknowledgment failures reset state and throw ShareAcknowledgmentException
- Container continues processing after individual record failures
- ShareAcknowledgment parameter injection follows existing Spring Kafka patterns
- Non-polymorphic listener method names (onShareRecord vs onMessage) prevent
potential conflicts with existing listener infrastructure and ensure clear
separation between regular and share consumer listener contracts
- Factory and container level configuration options provide flexibility
This implementation provides acknowledgment semantics for Kafka share groups
while maintaining backward compatibility with existing implicit acknowledgment behavior.
* Refactor share consumer acknowledgment interfaces and improve code quality
- Simplify to single AcknowledgingShareConsumerAwareMessageListener interface with nullable acknowledgment
- Remove redundant ShareConsumerAwareMessageListener interface
- Clean up ShareAcknowledgmentMode enum by removing unnecessary string property
- Replace verbose null checks with Boolean.TRUE.equals() pattern
- Use enum values for acknowledgment mode validation instead of hardcoded strings
- Update tests and documentation to use unified interface
- Fix spacing issues in @nullable annotations
- Fixing other formatting issues
Improve share consumer polling behavior and add isShareConsumer() helper
- Add isShareConsumer() helper method to AbstractKafkaListenerEndpoint for cleaner boolean checks
- Replace verbose Boolean.TRUE.equals() pattern with cleaner isShareConsumer() call
- Handle KIP-932 IllegalStateException when polling with unacknowledged records in explicit mode
- Add minimal 10ms delay to prevent tight loop while maintaining responsiveness
- Remove problematic pre-poll blocking logic that prevented proper exception handling
The share consumer now properly handles the broker's IllegalStateException when attempting
to poll with unacknowledged records, as specified in KIP-932. This maintains heartbeat
while waiting for acknowledgments and prevents CPU-intensive tight loops.
Fix thread safety in ShareConsumer acknowledgments
ShareConsumer is not thread-safe and requires all access to happen on the consumer thread.
The previous implementation allowed acknowledgment calls from listener threads to directly
access the consumer, causing ConcurrentModificationException.
Changes:
- Add PendingAcknowledgment queue to safely pass acknowledgments between threads
- Process queued acknowledgments on the consumer thread during poll loop
- Remove direct consumer access from ShareConsumerAcknowledgment.acknowledgeInternal()
- Add notifyAcknowledged() callback for acknowledgment completion
This ensures all ShareConsumer interactions happen on the owning consumer thread,
eliminating race conditions between polling and acknowledgment operations.
The thread safety issue was exposed by removing the pre-poll sleep, which previously
masked the concurrent access by creating timing windows where the consumer was dormant.
* Simplify share consumer acknowledgment configuration and consolidate message converters
- Replace ShareAcknowledgmentMode enum with boolean explicitShareAcknowledgment field
- Consolidate duplicate toMessage/toShareMessage methods into single toMessage with Object parameters
- Merge invoke/invokeHandler methods in MessagingMessageListenerAdapter to use Object parameters
- Eliminate duplicate commonHeaders methods in MessageConverter interface
- Add validation for explicit acknowledgment mode requiring proper listener interface
- Simplify ShareKafkaMessageListenerContainerUnitTests to focus on configuration validation
- Other formatting fixes in docs and javadocs
* Improve logging and test reliability for share consumer implementation
- Replace Thread.sleep() with CountDownLatch assertions in tests for
reliable synchronization and faster test execution
- Use LogMessage.format() instead of Supplier with String.format()
for consistent logging patterns
- Fix lambda expression to use effectively final variable in error logging
- Change shareConsumer field from nullable Boolean to primitive boolean
in AbstractKafkaListenerEndpoint for cleaner null handling
- Make utility methods static where appropriate for better code organization
* - Revert latch-based negative assertions back to Thread.sleep() in
constraint and integration tests, as testing for non-occurrence
(await expecting false) still blocks for full timeout duration
- Use chained assertion style for acknowledgment validations
* Consolidate share consumer constraint tests into integration tests
- Replace Thread.sleep() with Awaitility pattern that verifies poll blocking via trace log
- Add Mockito spy on LogAccessor to confirm the logging message
- Migrate shouldHandlePartialAcknowledgmentCorrectly test from ConstraintTests
- Migrate shouldHandleConcurrentAcknowledgmentAttempts test from ConstraintTests
- Fix topic collision by assigning unique topics to each test
- Remove duplicate ShareKafkaMessageListenerContainerConstraintTests class
This improves test reliability by verifying actual blocking behavior rather than
assuming Thread.sleep duration is sufficient, and eliminates test duplication.
* Refactor ShareKafkaListenerContainerFactory and fix compilation warnings
- Change autoStartup and phase from nullable wrappers to primitives with defaults
- Add @SuppressWarnings(NullAway.Init) to applicationEventPublisher and applicationContext
- Use ShareAcknowledgementMode.fromString() API instead of manual string parsing
- Use ArgumentMatchers with explicit type parameters to eliminate unchecked warnings in tests
- Remove deprecated imports from ShareRecordMessagingMessageListenerAdapter
- Use FQCN for JacksonProjectingMessageConverter and ProjectingMessageConverter
- Fix syntax error in kafka-queues.adoc documentation example
Signed-off-by: Soby Chacko <[email protected]>
When a record exceeds the timeout, you'll see a warning like:
442
+
----
443
+
WARN: Record not acknowledged within timeout (30 seconds).
444
+
In explicit acknowledgment mode, you must call ack.acknowledge(), ack.release(),
445
+
or ack.reject() for every record.
446
+
----
447
+
448
+
This feature helps developers quickly identify when acknowledgment calls are missing from their code, preventing the common issue of "Spring Kafka does not consume new records any more" due to forgotten acknowledgments.
Copy file name to clipboardExpand all lines: spring-kafka/src/main/java/org/springframework/kafka/annotation/KafkaListenerAnnotationBeanPostProcessor.java
0 commit comments