Project

General

Profile

Actions

개선(improvement) #2611

open

개선(improvement) #2310: [BE] Optimize Memory, CPU API search list flight

[BE] CRITICAL: AtomicReference Memory Retention in getListItinerary()

Added by Dante Le 3 months ago. Updated 3 months ago.

Status:
진행(Doing)
Priority:
높음(High)
Assignee:
Start date:
12/15/2025
Due date:
12/15/2025 (about 3 months late)
% Done:

0%

Estimated time:
Part:
Build env.:

Description

Problem

The getListItinerary() method (Lines 2769-2988) used AtomicReference to pass data between reactive pipeline steps, causing memory retention issues.

Original Anti-Pattern Code

Non-basket path:

AtomicReference<JsonNode> responseJsonNodeReference = new AtomicReference<>();
Mono<Void> getListAllMono = flightListAllService.getListAll(requestBody)
        .doOnNext(responseJsonNodeReference::set)
        .then();

Mono<JsonNode> convertMono = Mono.defer(() -> {
    return convertAllToItinerary(requestBody, responseJsonNodeReference.get());
});

return Flux.concat(getListAllMono).then(convertMono);

Basket path:

AtomicReference<FlightListItineraryBasketItemVo> basketItemReference = new AtomicReference<>();
AtomicReference<JsonNode> responseJsonNodeReference = new AtomicReference<>();
List<FlightListItineraryBasketSegmentVo> basketSegmentList = new ArrayList<>();

// Sequential execution
return Flux.concat(basketFlightItemMono, basketFlightSegmentMono,
    setBasketUseReqeustBodyMono, getListAllMono, findBasketFlightItemMono)
    .then(convertMono);

Solution

Non-basket path - Direct reactive chain:

return flightListAllService.getListAll(requestBody)
        .flatMap(responseJsonNode -> convertAllToItinerary(requestBody, responseJsonNode));

Basket path - Parallel execution with Mono.zip:

return Mono.zip(
        flightListItineraryFluxMapper.getBasketFlightItem(requestBodyMap),
        flightListItineraryFluxMapper.getBasketFlightSegmentList(requestBodyMap),
        flightListAllService.getListAll(requestBody)
).flatMap(tuple -> {
    FlightListItineraryBasketItemVo basketItem = tuple.getT1();
    List<FlightListItineraryBasketSegmentVo> basketSegmentList = tuple.getT2();
    JsonNode responseJsonNode = tuple.getT3();

    // Processing logic with direct variable access
    // Proper Mono.error() for exceptions

    return convertAllToItinerary(requestBody, responseJsonNode);
});

Improvements

  1. Memory: Eliminated AtomicReference holding 10-50 MB JsonNode beyond useful lifetime
  2. Performance: Parallel execution of 3 async operations instead of sequential (basket mode)
  3. Clarity: Removed confusing Mono.defer() + doOnNext() pattern
  4. Error Handling: Proper Mono.error() instead of throwing exceptions in Mono.fromRunnable()
  5. GC Pressure: Variables now scoped properly, eligible for GC immediately after use

Impact

  • Reduced memory retention by ~30-50% per basket request
  • Improved request latency in basket mode by enabling parallel database and vendor calls

File

web-api/src/main/java/com/ohmy/api/service/flight/FlightListItineraryService.java

Actions #1

Updated by Dante Le 3 months ago

  • Description updated (diff)
  • Status changed from 완료성공(Resolve) to 신규(New)
Actions #2

Updated by Dante Le 3 months ago

  • Parent task set to #2310
Actions #3

Updated by Dante Le 3 months ago

  • Subject changed from [BE] FIXED-1: AtomicReference Memory Retention in getListItinerary() to [BE] CRITICAL-1: AtomicReference Memory Retention in getListItinerary()
Actions #4

Updated by Dante Le 3 months ago

  • Subject changed from [BE] CRITICAL-1: AtomicReference Memory Retention in getListItinerary() to [BE] CRITICAL: AtomicReference Memory Retention in getListItinerary()
  • Due date set to 12/15/2025
  • Status changed from 신규(New) to 진행(Doing)
  • Start date set to 12/15/2025
  • Estimated time deleted (2.00 h)
Actions

Also available in: Atom PDF

Add picture from clipboard (Maximum size: 50 MB)