Chaturmind
LearnDSASystem DesignInterview PrepDevOpsEngineering GrowthBlog
Start learning
Chaturmind

Structured learning paths for engineers who want to go deep. Written by practitioners.

Learn

  • Java
  • DSA
  • System Design
  • Spring Boot
  • AI / ML
  • DevOps
  • Engineering Growth
  • Java Interview Prep

Company

  • Blog
  • Contact

Legal

  • Privacy Policy
  • Terms of Service

© 2026 Chaturmind. All rights reserved.

Built for engineers who want to go deep.


← Java Interview Prep: 5–8 Years

Advanced Core Java

  • Advanced OOP & Design Scenarios — Interview Questions
  • Advanced Concurrency, Collections & Memory — Interview Questions
  • Modern Java Language Features & Annotations — Interview Questions
  • Class Loading, Reflection, Serialization & Idioms — Interview Questions

Java Design Patterns in Depth

  • Design Patterns Overview & Singleton — Interview Questions
  • Factory & Abstract Factory Patterns — Interview Questions
  • Builder & Prototype Patterns — Interview Questions
  • Adapter & Bridge Patterns — Interview Questions
  • Composite & Decorator Patterns — Interview Questions
  • Facade & Proxy Patterns — Interview Questions
  • Chain of Responsibility & Observer Patterns — Interview Questions
  • Strategy & Template Method Patterns — Interview Questions
  • Command Pattern — Interview Questions

Advanced Spring Boot

  • Logging, Configuration & Actuator (Advanced) — Interview Questions
  • Transactions, Multiple Datasources & Query Tuning — Interview Questions
  • Validation & REST API Design (Advanced) — Interview Questions
  • Reactive, Async & Scheduling in Spring Boot — Interview Questions
  • Deployment, High Availability, Scaling & Caching — Interview Questions
Chaturmind
← Java Interview Prep: 5–8 Years

Advanced Core Java

  • Advanced OOP & Design Scenarios — Interview Questions
  • Advanced Concurrency, Collections & Memory — Interview Questions
  • Modern Java Language Features & Annotations — Interview Questions
  • Class Loading, Reflection, Serialization & Idioms — Interview Questions

Java Design Patterns in Depth

  • Design Patterns Overview & Singleton — Interview Questions
  • Factory & Abstract Factory Patterns — Interview Questions
  • Builder & Prototype Patterns — Interview Questions
  • Adapter & Bridge Patterns — Interview Questions
  • Composite & Decorator Patterns — Interview Questions
  • Facade & Proxy Patterns — Interview Questions
  • Chain of Responsibility & Observer Patterns — Interview Questions
  • Strategy & Template Method Patterns — Interview Questions
  • Command Pattern — Interview Questions

Advanced Spring Boot

  • Logging, Configuration & Actuator (Advanced) — Interview Questions
  • Transactions, Multiple Datasources & Query Tuning — Interview Questions
  • Validation & REST API Design (Advanced) — Interview Questions
  • Reactive, Async & Scheduling in Spring Boot — Interview Questions
  • Deployment, High Availability, Scaling & Caching — Interview Questions
HomeLearnJava Interview PrepJava Interview Prep: 5–8 YearsAdvanced Spring Boot
✓ FreeAdvanced· 8 min read

Reactive, Async & Scheduling in Spring Boot — Interview Questions

Asynchronous messaging scenarios (order processing via a broker), WebFlux and Project Reactor (Mono/Flux, event loop, when reactive pays off vs virtual threads), back-pressure in Reactive Streams, designing a scalable real-time processing pipeline, @Scheduled and @Async with properly configured executors, and heavy asynchronous image processing done safely.

Published September 25, 2026


How to use this lesson

Senior candidates are expected to say when not to use reactive programming. With Java 21 virtual threads, blocking-style code scales for most I/O-bound services. Also:

  • configure the executors behind @Async and @Scheduled deliberately;
  • know that in-process async work is lost on a crash, which is why durable work goes through a broker or a job table.

Q1. Describe a scenario where you'd use asynchronous messaging in Spring Boot.

Short answer: Order placement in e-commerce. The checkout API validates and saves the order, then publishes an OrderPlaced event to Kafka or RabbitMQ, and immediately returns 201/202 to the user. Separate consumers handle the slow or unreliable follow-ups at their own pace: sending emails and SMS, updating inventory, awarding loyalty points, fraud checks, analytics.

Key points to cover:

  • Benefits:
    • Faster responses.
    • Peaks are absorbed by the queue (load levelling).
    • Consumers scale independently.
    • Failures are isolated and retried, with a dead-letter topic.
  • Reliability:
    • Publish through the transactional outbox, so the database write and the event can't diverge.
    • Make consumers idempotent, because delivery is at-least-once.
    • Use a dead-letter topic for poison messages.
@KafkaListener(topics = "orders.placed", groupId = "notifications")
public void on(OrderPlaced event) {
    if (!processed.markIfNew(event.eventId())) return;          // idempotent consumer
    notifications.sendOrderConfirmation(event.orderId());
}

Learn it in depth → Event-Driven Architecture Patterns

Q2. What support does Spring Boot have for reactive programming?

Short answer: Spring WebFlux (spring-boot-starter-webflux) is a non-blocking web stack, running on Netty by default, built on Project Reactor:

  • Mono<T> carries 0 or 1 item, and Flux<T> carries 0..N items. Both are Reactive Streams publishers.
  • Annotated controllers, or functional routes (RouterFunction).
  • WebClient for non-blocking HTTP.
  • Reactive data access: R2DBC, reactive MongoDB, Redis and Cassandra.
  • Reactive security.
  • Reactive Kafka.
  • SSE and WebSockets streaming.
@GetMapping(value = "/prices/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
Flux<PriceTick> stream(@RequestParam String symbol) {
    return priceService.ticks(symbol)                          // an infinite Flux from a broker
            .sample(Duration.ofMillis(250))                    // throttle for the browser
            .onBackpressureLatest();
}

Key points to cover:

  • When it pays off:
    • Very high concurrency with mostly waiting on I/O;
    • streaming (SSE, WebSockets);
    • gateways and proxies (Spring Cloud Gateway is reactive);
    • fan-out calls composed without threads.
  • Costs:
    • A steeper learning curve.
    • Harder debugging and stack traces.
    • The whole chain must be non-blocking. One JDBC call on the event loop stalls every request.
  • Virtual threads (spring.threads.virtual.enabled=true, Boot 3.2+) give most of the scalability to ordinary blocking MVC code. So choose WebFlux mainly for streaming and back-pressure needs.

Q3. How is back-pressure handled in reactive streams?

Short answer: Reactive Streams is a pull-based contract. A subscriber calls Subscription.request(n) to say how many items it can take, and the publisher must not emit more than was requested. Demand propagates upstream through the operator chain. So a slow consumer naturally slows the producer, instead of piling items into memory.

Key points to cover:

  • When the source can't be slowed down (UI events, market ticks, a hot broker stream), choose an overflow strategy:
    • onBackpressureBuffer(max, …): buffer, with a bound;
    • onBackpressureDrop();
    • onBackpressureLatest(): keep only the newest;
    • sample/window/buffer: batch or throttle;
    • limitRate(n): prefetch tuning.
  • Across the network: HTTP/TCP flow control, and RSocket carries request(n) between services. Plain HTTP JSON arrays don't.
  • publishOn/subscribeOn move work between schedulers. Their queues are bounded too.

Q4. You need a highly scalable real-time data processing application. How would you use Spring Boot's reactive features?

Short answer: Build a streaming pipeline from source to sink:

  • Ingest: consume from Kafka with Reactor Kafka, or Spring Cloud Stream reactive functions (Function<Flux<In>, Flux<Out>>), or accept WebSocket or RSocket streams.
  • Process non-blockingly:
    • Parse, filter and enrich, with flatMap(…, concurrency) to bound the in-flight calls.
    • Use WebClient, or a reactive Redis cache, for lookups.
    • Use window/bufferTimeout for micro-batches.
    • Use groupBy per key for ordered, per-entity processing.
  • Sink: R2DBC or reactive Mongo bulk writes, or produce to downstream topics. Push live results to dashboards with SSE.
  • Resilience:
    • timeout, retryWhen(Retry.backoff(...)), and onErrorContinue avoided, in favour of explicit error-to-DLQ handling.
    • Bounded buffers everywhere.
    • Commit Kafka offsets only after successful processing.
  • Scale out: partitions × consumer instances. Stateless processing nodes let you scale horizontally, and Kubernetes autoscales on consumer lag.
  • Observe: Micrometer metrics on the Reactor operators, consumer lag, and Reactor's context propagation for tracing.

Common trap: calling a blocking library (JDBC, a legacy SDK) inside map or flatMap. If you must, wrap it with Mono.fromCallable(...).subscribeOn(Schedulers.boundedElastic()), and treat it as a design smell.

Q5. How does Spring handle scheduling and task execution?

Short answer:

  • Scheduling: add @EnableScheduling, then @Scheduled methods:
    • fixedRate: start every N, regardless of the previous run;
    • fixedDelay: wait N after the previous run finishes;
    • initialDelay;
    • cron (6 fields in Spring, including seconds), with a zone.
  • Async execution: add @EnableAsync. Methods marked @Async run on a TaskExecutor, returning void or CompletableFuture<T>.
  • The underlying abstractions are TaskScheduler/TaskExecutor. Boot auto-configures ThreadPoolTaskScheduler (by default a single thread, so one slow job delays the others) and ThreadPoolTaskExecutor, tuned with spring.task.scheduling.* and spring.task.execution.*, or virtual threads.
spring:
  task:
    scheduling:
      pool:
        size: 4
    execution:
      pool:
        core-size: 8
        max-size: 16
        queue-capacity: 500

Key points to cover:

  • Clusters: with N instances, every instance runs every @Scheduled job. Use ShedLock (a database or Redis lock), Quartz in clustered mode, or a Kubernetes CronJob, so a job runs once.
  • Scheduled methods should be idempotent, and catch or log their exceptions. Otherwise failures go only to the error handler.

Q6. You need to process heavy image files asynchronously. How would you set this up?

Short answer: For quick wins, use @Async with a dedicated, bounded executor. For robustness, use a queue-backed job:

  1. Upload: stream the file to object storage (S3 or GCS), not into memory. Create a ImageJob(PENDING) row, and return 202 Accepted with /jobs/{id}, or notify later through a webhook or WebSocket.
  2. Process:
    • Single instance, loss-tolerant: an @Async("imageExecutor") method.
    • Production: publish a message (Kafka, SQS or RabbitMQ). Workers (which can be a separate deployment, autoscaled on queue depth) process it with retries and a DLQ. Crashes don't lose work.
  3. Bound resources:
    • A pool sized for CPU-bound work (≈ the number of cores).
    • A bounded queue with a rejection policy (CallerRunsPolicy, or reject with 429 or 503).
    • Memory limits, since decoded images are large, and a timeout per job.
  4. Track and observe: job status transitions, and metrics (queue depth, durations, failures).
@Configuration @EnableAsync
class AsyncConfig {
    @Bean("imageExecutor")
    ThreadPoolTaskExecutor imageExecutor() {
        var ex = new ThreadPoolTaskExecutor();
        ex.setCorePoolSize(Runtime.getRuntime().availableProcessors());
        ex.setMaxPoolSize(Runtime.getRuntime().availableProcessors());
        ex.setQueueCapacity(200);                                            // bounded: back-pressure instead of OOM
        ex.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        ex.setThreadNamePrefix("img-");
        ex.setTaskDecorator(new ContextCopyingDecorator());                  // MDC/trace/security context
        ex.initialize();
        return ex;
    }
}

@Service
class ImageProcessor {
    @Async("imageExecutor")
    public CompletableFuture<Void> process(UUID jobId) {
        // download from storage → resize/compress (thumbnails, WebP) → upload variants → mark job DONE
        return CompletableFuture.completedFuture(null);
    }
}

Common traps:

  • @Async on a method called from the same class (the proxy is bypassed, so it runs synchronously).
  • Using the default unbounded queue: the pool never grows beyond the core size, and the queue can exhaust memory.
  • Losing work on restart with in-memory async. Use a durable queue for anything that matters.

Follow-up questions this topic invites — and their answers

Q: WebFlux or MVC with virtual threads for a new service? A: Default to MVC + virtual threads: simpler code, blocking libraries (JDBC, JPA) work, and it scales for I/O-bound work. Choose WebFlux for streaming (SSE, WebSockets), back-pressure-sensitive pipelines, gateways, or a codebase that's already reactive end to end.

Q: How do you handle exceptions from @Async methods? A: For CompletableFuture returns, the caller handles them (exceptionally, handle). For void methods, configure an AsyncUncaughtExceptionHandler (through AsyncConfigurer). Otherwise the exceptions are only logged.

Q: How do you propagate the MDC, tracing and security context to async threads? A: Use a TaskDecorator that captures the context on submit and restores it in the worker. Micrometer's ContextSnapshot or ContextPropagatingTaskDecorator does this for observations. For security, use DelegatingSecurityContextAsyncTaskExecutor. Reactor uses its Context, plus automatic context propagation (Hooks).

Q: fixedRate vs fixedDelay when a run takes longer than the interval? A: With the default single-threaded scheduler, fixedRate runs back-to-back, catching up with no overlap. fixedDelay always waits the full delay after completion. Concurrent overlap only happens if you add @Async or use a larger pool.

Previous

Validation & REST API Design (Advanced) — Interview Questions

Next

Deployment, High Availability, Scaling & Caching — Interview Questions

AI Tutor

Lesson: Reactive, Async & Scheduling in Spring Boot — Interview Questions

Quick actions

AI responses can be inaccurate. Verify critical information.