Java, Spring & Kafka Fundamentals Deep-Dive
Wells FargoSoftware Engineer · Technical ScreenLast updated
Tests practical knowledge of Java concurrency and memory visibility, Kafka at-least-once delivery and idempotency patterns, and Spring Security context propagation across asynchronous thread boundaries.
Scenario: Reliable Asynchronous Transaction Processing Service
You are tasked with reviewing and stabilizing a high-throughput payment ingestion microservice built with Java 17, Spring Boot 3, and Apache Kafka. The service consumes payment authorization events from a Kafka topic (payment-authorizations), enriches each event with user risk data asynchronously via an internal REST client, and persists the final transaction to an RDBMS (PostgreSQL).
During peak load testing, the team identified three critical defects:
- Security Context Loss: Downstream calls made inside asynchronous tasks fail with
401 Unauthorizedbecause the SpringSecurityContextis missing. - Duplicate Ledger Postings: Under network jitter and consumer group rebalances, multiple instances process the same Kafka record, causing duplicate debit records in the database.
- State Corruption & Leaks: An internal in-memory metrics cache using a standard
HashMapintermittently corrupts counts or throwsConcurrentModificationException.
Provide concrete architectural and implementation strategies to resolve each issue.
Questions to Address
1. Spring Security & Thread Context Propagation
- Explain why
SecurityContextHolder.getContext()returns an unauthenticated or empty context inside child threads spawned byCompletableFuture.supplyAsync()or a customThreadPoolTaskExecutor. - Detail two ways to properly propagate security credentials across thread boundaries in Spring Boot, including the specific risks associated with
SecurityContextHolder.MODE_INHERITABLETHREADLOCALwhen thread pools are reused.
2. Kafka Delivery Semantics & Idempotent Processing
- Explain the default consumer offset commit behavior in Spring Kafka (
enable.auto.commit=truevsAckMode.MANUAL_IMMEDIATE). Why does at-least-once delivery cause duplicate processing during consumer rebalances? - Propose an end-to-end idempotency strategy to ensure that duplicate Kafka deliveries never result in duplicate database writes. Include the database constraints and state check mechanism you would employ.
- How should the consumer handle a unrecoverable "poison pill" payload without blocking partition processing indefinitely?
3. Java Concurrency & Transactional Boundaries
- Contrast the thread-safety and performance characteristics of
ConcurrentHashMap,Collections.synchronizedMap(), and using aReentrantLockfor high-concurrency read-heavy metrics tracking. - What happens if a database commit succeeds inside a
@TransactionalSpring service method, but the Kafka offset commit subsequently fails? How do you resolve dual-write inconsistency between Kafka and the database?
Hints
Hint 1
Consider how Spring's `DelegatingSecurityContextAsyncTaskExecutor` or `SecurityContextCallable` manages context cleanup when thread pool worker threads are returned to the pool.
Hint 2
For Kafka duplicate handling, evaluate unique constraint deduplication tables or the transactional outbox pattern combined with an idempotent consumer check.
Hint 3
Remember that `ConcurrentHashMap` utilizes lock striping and compare-and-swap (CAS) primitives on bucket heads, avoiding a global mutex.
Follow-up questions
- If your Kafka consumer group rebalances while a batch of messages is actively being processed by worker threads, how do you prevent split-brain processing of the same partition?
- How does Spring Kafka's `DefaultErrorHandler` with backoff and Dead Letter Publishing (DeadLetterPublishingRecoverer) prevent poison-pill deadlocks?
- If you needed strictly ordered transaction processing per bank account, how would you partition the Kafka topic and configure the Spring `@KafkaListener` concurrency?
Solution walkthrough is for members
Get the full walkthrough with reference code and complexity analysis, plus Kitty Coach at 300 messages a day. Hints, the code runner and community answers stay free.