Skip to content

Troubleshooting

TAEHEON KIM edited this page Jul 5, 2026 · 8 revisions

Troubleshooting

1. ๋™์‹œ ์ง€์› ๋ ˆ์ด์Šค์ปจ๋””์…˜

์ฆ์ƒ: 20๋ช…์ด ๋™์‹œ์— ๊ฐ™์€ ๊ฒŒ์‹œ๊ธ€์— ์ง€์› ์‹œ DataIntegrityViolationException ๋ฐœ์ƒ, ์ผ๋ถ€ ์š”์ฒญ 500 ์—๋Ÿฌ

์›์ธ: SELECT(์ค‘๋ณต ์ฒดํฌ) -> INSERT ์‚ฌ์ด์— ๋‹ค๋ฅธ ํŠธ๋žœ์žญ์…˜์ด ๋ผ์–ด๋“ค์–ด ์œ ๋‹ˆํฌ ์ œ์•ฝ ์œ„๋ฐ˜

ํ•ด๊ฒฐ:

@Lock(LockModeType.PESSIMISTIC_WRITE)
@QueryHints(QueryHint(name = JAKARTA_LOCK_TIMEOUT, value = "3000"))
fun findByPostIdWithLock(postId: UUID): StudyPost?
  • ๋น„๊ด€์  ๋ฝ์œผ๋กœ ๊ฒŒ์‹œ๊ธ€ ํ–‰ ์„ ์ 
  • ๋ฝ ํƒ€์ž„์•„์›ƒ 3์ดˆ๋กœ ๋ฌดํ•œ ๋Œ€๊ธฐ ๋ฐฉ์ง€
  • DataIntegrityViolationException catch -> 409 ์‘๋‹ต
  • ๋ฝ ํš๋“ ์ˆœ์„œ๋ฅผ ํ•ญ์ƒ ๊ฒŒ์‹œ๊ธ€ -> ์ง€์› ๋‹จ๋ฐฉํ–ฅ ๊ณ ์ •์œผ๋กœ ๋ฐ๋“œ๋ฝ ์ œ๊ฑฐ

2. ์•Œ๋ฆผ ์ฒ˜๋ฆฌ๋กœ ์ธํ•œ API ์‘๋‹ต ์ง€์—ฐ

์ฆ์ƒ: ๋Œ“๊ธ€ ์ž‘์„ฑ API p(95) ๊ธ‰๋“ฑ, ์—๋Ÿฌ์œจ 87%

์›์ธ: ๋Œ“๊ธ€ ์ €์žฅ + ์•Œ๋ฆผ DB ์ €์žฅ + Redis Pub/Sub ๋ฐœํ–‰์ด ๋™๊ธฐ ์ฒ˜๋ฆฌ -> ์ปค๋„ฅ์…˜ ์ฆ‰์‹œ ๊ณ ๊ฐˆ

ํ•ด๊ฒฐ: @Async("notificationExecutor")๋กœ ์•Œ๋ฆผ ์ฒ˜๋ฆฌ ๋ถ„๋ฆฌ

@Bean(name = ["notificationExecutor"])
fun notificationExecutor(): Executor {
    val executor = SimpleAsyncTaskExecutor("notification-")
    executor.setVirtualThreads(true)
    executor.setTaskDecorator(mdcTaskDecorator())
    return executor
}

ThreadPoolExecutor.DiscardPolicy ์ ์šฉ โ€” ํ’€ ํฌํ™” ์‹œ ์•Œ๋ฆผ๋งŒ ์กฐ์šฉํžˆ ๋ฒ„๋ฆฌ๊ณ  API ์ •์ƒ ์‘๋‹ต ์œ ์ง€

๊ฒฐ๊ณผ: ์—๋Ÿฌ์œจ 87% -> 2.3%, RPS 137 -> 940 (585% ํ–ฅ์ƒ)


3. ๋น„๋™๊ธฐ ์Šค๋ ˆ๋“œ์—์„œ MDC ์ปจํ…์ŠคํŠธ ์†Œ์‹ค

์ฆ์ƒ: @Async ์ฒ˜๋ฆฌ ์‹œ ๋กœ๊ทธ์— requestId, userId๊ฐ€ ๋น ์ ธ Kibana์—์„œ ์š”์ฒญ ์ถ”์  ๋ถˆ๊ฐ€

์›์ธ: MDC๋Š” ThreadLocal ๊ธฐ๋ฐ˜ -> ๋ถ€๋ชจ ์Šค๋ ˆ๋“œ์˜ ์ปจํ…์ŠคํŠธ๊ฐ€ ์ž์‹ ์Šค๋ ˆ๋“œ๋กœ ์ „ํŒŒ๋˜์ง€ ์•Š์Œ

ํ•ด๊ฒฐ: TaskDecorator๋กœ ๋น„๋™๊ธฐ ์‹คํ–‰ ์ „ MDC ์ปจํ…์ŠคํŠธ ์บก์ฒ˜ ํ›„ ์ฃผ์ž…

private fun mdcTaskDecorator(): TaskDecorator = TaskDecorator { task ->
    val mdcContext = MDC.getCopyOfContextMap()
    Runnable {
        try {
            if (mdcContext != null) MDC.setContextMap(mdcContext)
            task.run()
        } finally {
            MDC.clear()
        }
    }
}

4. ๋ฉ€ํ‹ฐ ์ธ์Šคํ„ด์Šค ์•Œ๋ฆผ, ์ฑ„ํŒ… ๋ฏธ์ˆ˜์‹ 

์ฆ์ƒ: App1์— ์—ฐ๊ฒฐ๋œ ํด๋ผ์ด์–ธํŠธ๊ฐ€ ๋ณด๋‚ธ ์ฑ„ํŒ…์ด App2์— ์—ฐ๊ฒฐ๋œ ํด๋ผ์ด์–ธํŠธ์—๊ฒŒ ์ „๋‹ฌ ์•ˆ ๋จ

์›์ธ: WebSocket STOMP ์„ธ์…˜์€ ์ธ์Šคํ„ด์Šค๋ณ„๋กœ ๋…๋ฆฝ์  -> ๋‹ค๋ฅธ ์ธ์Šคํ„ด์Šค์˜ ์—ฐ๊ฒฐ์— ์ ‘๊ทผ ๋ถˆ๊ฐ€

ํ•ด๊ฒฐ: Redis Pub/Sub์œผ๋กœ ์ธ์Šคํ„ด์Šค ๊ฐ„ ๋ธŒ๋กœ๋“œ์บ์ŠคํŠธ

  • ์ฑ„ํŒ…: RedisChatPublisherAdapter.publish() -> ์ „ ์ธ์Šคํ„ด์Šค ๊ตฌ๋… -> ๊ฐ์ž WebSocket ์ „๋‹ฌ
  • ์•Œ๋ฆผ: Kafka Consumer -> Redis Pub/Sub -> ์ „ ์ธ์Šคํ„ด์Šค -> SSE ์ „๋‹ฌ

5. Kafka ๋ฐœํ–‰ ์‹คํŒจ ์‹œ ์•Œ๋ฆผ ์œ ์‹ค

์ฆ์ƒ: Kafka ๋ธŒ๋กœ์ปค ์ผ์‹œ ์žฅ์•  ์‹œ ์•Œ๋ฆผ ์ด๋ฒคํŠธ ์†Œ๋ฉธ

์›์ธ: ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ด๋ฒคํŠธ ๋ฐœํ–‰ ํ›„ Kafka ์ „์†ก ์‹คํŒจ ์‹œ ์žฌ์‹œ๋„ ์ˆ˜๋‹จ ์—†์Œ

ํ•ด๊ฒฐ: Outbox ํŒจํ„ด ๋„์ž… ์•Œ๋ฆผ ์ด๋ฒคํŠธ ๋ฐœ์ƒ -> Outbox DB ์ €์žฅ (๊ฐ™์€ ํŠธ๋žœ์žญ์…˜) -> Kafka ๋ฐœํ–‰ ์‹œ๋„ -> ์‹คํŒจ ์‹œ OutboxRetryScheduler๊ฐ€ PENDING ์ƒํƒœ ์žฌ์‹œ๋„ -> ์˜๊ตฌ ์‹คํŒจ ์‹œ FAILED ์ฒ˜๋ฆฌ ํ›„ DLT ๊ฒฉ๋ฆฌ


6. CI ๋นŒ๋“œ ์‹œ jOOQ ์ฝ”๋“œ ์ƒ์„ฑ ์‹คํŒจ

์ฆ์ƒ: GitHub Actions์—์„œ generateJooq ํƒœ์Šคํฌ ์‹คํ–‰ ์‹œ DB ์—ฐ๊ฒฐ ์—†์–ด ๋นŒ๋“œ ์‹คํŒจ

์›์ธ: jOOQ ์ฝ”๋“œ ์ƒ์„ฑ์ด ์‹ค์ œ DB ์Šคํ‚ค๋งˆ๋ฅผ ์ฝ์–ด์•ผ ํ•˜๋Š”๋ฐ CI ํ™˜๊ฒฝ์— DB ์—†์Œ

ํ•ด๊ฒฐ: CI Gradle ๋ช…๋ น์— -x generateJooq ์ถ”๊ฐ€๋กœ ํƒœ์Šคํฌ ์Šคํ‚ต. ์ƒ์„ฑ๋œ jOOQ ํด๋ž˜์Šค๋Š” ์†Œ์Šค๋กœ ์ปค๋ฐ‹ํ•ด CI์—์„œ ๋ณ„๋„ ์ƒ์„ฑ ์—†์ด ๋นŒ๋“œ


7. IdempotencyFilter ์‘๋‹ต ์ด์ค‘ ์“ฐ๊ธฐ

์ฆ์ƒ: Idempotency-Key ํ—ค๋”๊ฐ€ ์žˆ๋Š” ์š”์ฒญ์—์„œ Trailing token found after value Jackson ์—ญ์ง๋ ฌํ™” ์˜ค๋ฅ˜ ๋ฐœ์ƒ

์›์ธ: IdempotencyResponseWrapper.flushBuffer()๊ฐ€ ์‹ค์ œ response์— body๋ฅผ ์“ฐ๊ณ , IdempotencyFilter์—์„œ๋„ wrapper.flushBuffer()๋ฅผ ๋ช…์‹œ์ ์œผ๋กœ ํ˜ธ์ถœํ•ด body๊ฐ€ ๋‘ ๋ฒˆ write๋จ

ํ•ด๊ฒฐ:

  • flushBuffer()์—์„œ ์‹ค์ œ response ์“ฐ๊ธฐ ์ œ๊ฑฐ (๋‚ด๋ถ€ ๋ฒ„ํผ flush๋งŒ ์ˆ˜ํ–‰)
  • IdempotencyFilter์—์„œ ์บก์ฒ˜ํ•œ body๋ฅผ ๋”ฑ ํ•œ ๋ฒˆ๋งŒ response์— ์“ฐ๋„๋ก ์ˆ˜์ •
  • status code๋„ ํ•จ๊ป˜ ์บ์‹œ("201|{body}" ํ˜•์‹)ํ•ด ์žฌ์‘๋‹ต ์‹œ ์›๋ž˜ ์ƒํƒœ ์ฝ”๋“œ ๋ณต์›
// ์ˆ˜์ • ์ „: flushBuffer()์—์„œ response์— write -> filter์—์„œ๋„ write -> ์ด์ค‘ ์“ฐ๊ธฐ
// ์ˆ˜์ • ํ›„: filter์—์„œ๋งŒ write
val capturedBody = wrapper.capturedBody
val capturedStatus = wrapper.statusCode
idempotencyStoragePort.set(redisKey, "$capturedStatus|$capturedBody", TTL)
response.status = capturedStatus
response.writer.write(capturedBody)

8. Redis ์บ์‹œ ์—ญ์ง๋ ฌํ™” ์˜ค๋ฅ˜ (Jackson 3.x)

์ฆ์ƒ: ๊ฒŒ์‹œ๊ธ€ ๋‹จ๊ฑด ์กฐํšŒ ์‹œ Redis ์บ์‹œ ์—ญ์ง๋ ฌํ™” ์‹คํŒจ, Cannot construct instance of StudyPostResponse (no Creators) ์˜ค๋ฅ˜

์›์ธ: Spring Boot 4.x๋Š” Jackson 3.x(tools.jackson)๋ฅผ ์‚ฌ์šฉํ•˜๋Š”๋ฐ, Kotlin data class์— @JsonCreator๊ฐ€ ์—†์œผ๋ฉด ์—ญ์ง๋ ฌํ™” ์‹œ ์ƒ์„ฑ์ž๋ฅผ ์ฐพ์ง€ ๋ชปํ•จ

ํ•ด๊ฒฐ: StudyPostResponse์— @JsonCreator + ๊ฐ ํŒŒ๋ผ๋ฏธํ„ฐ์— @JsonProperty ์ถ”๊ฐ€

data class StudyPostResponse @JsonCreator constructor(
    @JsonProperty("id") val id: UUID,
    @JsonProperty("title") val title: String,
    ...
)

๋™์ผ ๋ฌธ์ œ ๋ฐœ์ƒ ์œ„์น˜: KakaoIdTokenPayload, KakaoTokenResponse๋„ ๊ฐ™์€ ๋ฐฉ์‹์œผ๋กœ ์ˆ˜์ •


9. ์ค‘๋ณต ์ง€์› ๋น„์ฆˆ๋‹ˆ์Šค ๋ฃฐ ๋ˆ„๋ฝ

์ฆ์ƒ: ๋™์ผ ์‚ฌ์šฉ์ž๊ฐ€ ๋‹ค๋ฅธ Idempotency-Key๋กœ ๊ฐ™์€ ๊ฒŒ์‹œ๊ธ€์— ์žฌ์ง€์› ์‹œ ์ค‘๋ณต ์ €์žฅ

์›์ธ: Idempotency-Key๋Š” ๋„คํŠธ์›Œํฌ ์žฌ์‹œ๋„๋งŒ ๋ฐฉ์ง€ํ•˜๋ฉฐ, ์‚ฌ์šฉ์ž๊ฐ€ ์˜๋„์ ์œผ๋กœ ๋‹ค์‹œ ์ง€์›ํ•˜๋Š” ๊ฒฝ์šฐ๋Š” ๋น„์ฆˆ๋‹ˆ์Šค ๋ฃฐ๋กœ ๋ง‰์•„์•ผ ํ•จ

ํ•ด๊ฒฐ: ๋„๋ฉ”์ธ ์—”ํ‹ฐํ‹ฐ์— ์ค‘๋ณต ๊ฒ€์ฆ ์ถ”๊ฐ€

// StudyPost.kt
fun validateNotDuplicateApply(alreadyApplied: Boolean) {
    if (alreadyApplied) throw CustomException(ErrorCode.ALREADY_APPLIED)
}

// ApplyStudyPostService.kt
post.validateNotDuplicateApply(
    applyRepository.existsByPostIdAndApplicantId(postId, userId)
)

10. ์ŠคํŒŒ์ดํฌ ํ…Œ์ŠคํŠธ dial: i/o timeout

์ฆ์ƒ: 15,000 VU ์ŠคํŒŒ์ดํฌ ํ…Œ์ŠคํŠธ์—์„œ dial: i/o timeout ๋ฐœ์ƒ, ์—๋Ÿฌ์œจ 100%

์›์ธ: Tomcat accept ํ(๊ธฐ๋ณธ 200๊ฐœ) ํฌํ™” -> TCP ์—ฐ๊ฒฐ ์‹œ๋„์กฐ์ฐจ ํƒ€์ž„์•„์›ƒ ์„œ๋ฒ„๊ฐ€ ์‘๋‹ต์„ ๋ชป ์ฃผ๋Š” ๊ฒŒ ์•„๋‹ˆ๋ผ ์—ฐ๊ฒฐ ์ž์ฒด๊ฐ€ OS ๋ ˆ๋ฒจ์—์„œ ๋“œ๋กญ๋จ

๋ถ„์„: accept-count๋ฅผ ๋Š˜๋ฆฌ๋ฉด ๋น ๋ฅธ ์‹คํŒจ(Fail Fast) ์›์น™์— ์–ด๊ธ‹๋‚จ. ๊ทผ๋ณธ ์›์ธ์€ ๋‹จ์ผ ์„œ๋ฒ„ ์ธ์Šคํ„ด์Šค ํ•œ๊ณ„ โ€” k6์™€ ์•ฑ์ด ๊ฐ™์€ ๋จธ์‹ ์—์„œ ์ž์› ๊ฒฝ์Ÿ

๊ฒฐ๋ก : ์„ค์ •๊ฐ’์œผ๋กœ ํ•ด๊ฒฐํ•  ๋ฌธ์ œ๊ฐ€ ์•„๋‹Œ ๋‹จ์ผ ์„œ๋ฒ„ ํ•œ๊ณ„. ์‹ค๋ฌด๋ผ๋ฉด Auto Scaling์œผ๋กœ ์ˆ˜ํ‰ ํ™•์žฅ, prod ํ™˜๊ฒฝ 2๊ฐœ ์ธ์Šคํ„ด์Šค + Nginx ๋กœ๋“œ๋ฐธ๋Ÿฐ์‹ฑ ๊ตฌ์„ฑ์ด ์ด๋ฏธ ๋˜์–ด ์žˆ์Œ


11. ์ŠคํŒŒ์ดํฌ ํ…Œ์ŠคํŠธ ํ•œ๊ธ€ URL ์ธ์ฝ”๋”ฉ ์˜ค๋ฅ˜

์ฆ์ƒ: spike-search.js์—์„œ Invalid character found in the request target ์˜ค๋ฅ˜, ๊ฒ€์ƒ‰ ์š”์ฒญ 62% ์‹คํŒจ

์›์ธ: k6์—์„œ ํ•œ๊ธ€ ํ‚ค์›Œ๋“œ๋ฅผ URL ์ธ์ฝ”๋”ฉ ์—†์ด ๊ทธ๋Œ€๋กœ ์ „์†ก -> Tomcat์ด RFC 7230/3986 ์œ„๋ฐ˜์œผ๋กœ ์š”์ฒญ ๊ฑฐ๋ถ€ (400)

ํ•ด๊ฒฐ: encodeURIComponent() ์ ์šฉ

// ์ˆ˜์ • ์ „
const res = http.get(`${BASE_URL}/api/posts/search?keyword=${keyword}`);

// ์ˆ˜์ • ํ›„
const keyword = encodeURIComponent(KEYWORDS[__VU % KEYWORDS.length]);
const res = http.get(`${BASE_URL}/api/posts/search?keyword=${keyword}`);

12. ์ŠคํŒŒ์ดํฌ ํ…Œ์ŠคํŠธ Idempotency ์บ์‹œ๋กœ ์ธํ•œ ํ…Œ์ŠคํŠธ ์‹คํŒจ

์ฆ์ƒ: ์ƒˆ ํ† ํฐ์œผ๋กœ spike-idempotency.js ์žฌ์‹คํ–‰ ์‹œ์—๋„ 100% ์‹คํŒจ

์›์ธ: ์ด์ „ ์‹คํŒจ ํ…Œ์ŠคํŠธ(๋งŒ๋ฃŒ ํ† ํฐ์œผ๋กœ ์‹คํ–‰)์—์„œ 401 ์‘๋‹ต์ด Redis์— ์บ์‹œ๋จ (idem-test-{VU} ํ‚ค๋กœ "401|..." ์ €์žฅ, TTL 24์‹œ๊ฐ„) ์ƒˆ ํ† ํฐ์œผ๋กœ ์žฌ์‹คํ–‰ํ•ด๋„ ๋™์ผ ํ‚ค๋กœ ์บ์‹œ๋œ 401 ์‘๋‹ต ๋ฐ˜ํ™˜

ํ•ด๊ฒฐ: ํ…Œ์ŠคํŠธ ์‹คํ–‰๋งˆ๋‹ค ๊ณ ์œ ํ•œ ํ‚ค prefix ์‚ฌ์šฉ const RUN_ID = Date.now();

export default function () { const idempotencyKey = idem-test-${RUN_ID}-${__VU}; // ... } ์‹คํ–‰ ๋‹จ์œ„๋กœ ํ‚ค๊ฐ€ ๋‹ฌ๋ผ์ ธ ์ด์ „ ์บ์‹œ์™€ ์ถฉ๋Œํ•˜์ง€ ์•Š์Œ


13. ๋น„๊ด€์  ๋ฝ ์ฟผ๋ฆฌ์˜ ๋ถˆํ•„์š”ํ•œ JOIN FETCH๋กœ ์ธํ•œ ๋ฝ ๋ฒ”์œ„ ํ™•๋Œ€

์ฆ์ƒ: ๋ฝ ์ฟผ๋ฆฌ ์ ๊ฒ€ ์ค‘, ์ง€์› ๋™์‹œ์„ฑ ์ œ์–ด์— ์“ฐ์ด๋Š” PESSIMISTIC_WRITE ์ฟผ๋ฆฌ๊ฐ€ ๋ฝ ๋Œ€์ƒ ์—”ํ‹ฐํ‹ฐ ์™ธ์— ์—ฐ๊ด€ ์—”ํ‹ฐํ‹ฐ๊นŒ์ง€ JOIN FETCHํ•˜๊ณ  ์žˆ๋Š” ๊ฒƒ์„ ๋ฐœ๊ฒฌ. SELECT ... FOR UPDATE๊ฐ€ ์กฐ์ธ๋œ ํ…Œ์ด๋ธ” ํ–‰๊นŒ์ง€ ํ•จ๊ป˜ ์ž ๊ฐ€, ๊ฒŒ์‹œ๊ธ€ ํ•˜๋‚˜์— ์ง€์›์ด ๋ชฐ๋ฆด ๋•Œ ๊ทธ ๊ฒŒ์‹œ๊ธ€ ์ž‘์„ฑ์ž์˜ User ํ–‰์ด ๋งค ์ง€์› ์š”์ฒญ๋งˆ๋‹ค ๋ฐ˜๋ณต์ ์œผ๋กœ ์ž ๊ธฐ๋Š” ๊ตฌ์กฐ์˜€์Œ โ€” ์ž‘์„ฑ์ž์™€ ๋ฌด๊ด€ํ•œ ์ง€์› ํŠธ๋žœ์žญ์…˜๋“ค์ด ์ž‘์„ฑ์ž์˜ User ํ–‰์„ ๋‘๊ณ  ๋ถˆํ•„์š”ํ•˜๊ฒŒ ๊ฒฝํ•ฉ.

์›์ธ: ์ง€์› ๋ฝ ์ฟผ๋ฆฌ(findByIdWithPostAndApplicantForUpdate)์™€ ๊ฒŒ์‹œ๊ธ€ ๋ฝ ์ฟผ๋ฆฌ (findByIdWithAuthorForUpdate)๊ฐ€ ์‹ค์ œ๋กœ๋Š” ํ•„๋“œ๋ฅผ ์“ฐ์ง€ ์•Š๋Š” ์—ฐ๊ด€๊ด€๊ณ„(a.applicant, p.author)๊นŒ์ง€ JOIN FETCHํ•˜๊ณ  ์žˆ์—ˆ์Œ. ๋ฝ ๋Œ€์ƒ ํ–‰ ํ•˜๋‚˜๋งŒ ์ž ๊ทธ๋ ค๋Š” ์˜๋„์™€ ๋‹ฌ๋ฆฌ, JPA๊ฐ€ ์ƒ์„ฑํ•œ FOR UPDATE ์ฟผ๋ฆฌ๋Š” ์กฐ์ธ์— ํฌํ•จ๋œ ๋ชจ๋“  ํ…Œ์ด๋ธ” ํ–‰์„ ์ž ๊ธˆ ๋ฒ”์œ„์— ํฌํ•จ์‹œํ‚ด.

ํ•ด๊ฒฐ:

// ์ˆ˜์ • ์ „: a.applicant๊นŒ์ง€ JOIN FETCH -> applicant(User) ํ–‰๋„ ๋ฝ ๋ฒ”์œ„์— ํฌํ•จ
@Lock(LockModeType.PESSIMISTIC_WRITE)
@Query("SELECT a FROM ApplyJpaEntity a JOIN FETCH a.post JOIN FETCH a.applicant WHERE a.id = :applyId")

// ์ˆ˜์ • ํ›„: ์‹ค์ œ ๊ฐ’์ด ํ•„์š”ํ•œ a.post๋งŒ ์œ ์ง€, ๋ฏธ์‚ฌ์šฉ a.applicant ์ œ๊ฑฐ
@Lock(LockModeType.PESSIMISTIC_WRITE)
@Query("SELECT a FROM ApplyJpaEntity a JOIN FETCH a.post WHERE a.id = :applyId")
fun findByIdWithPostAndApplicantForUpdate(...)
  • ๋ฝ ์ฟผ๋ฆฌ๋Š” ์‹ค์ œ ํ•„๋“œ ์‚ฌ์šฉ ์—ฌ๋ถ€ ๊ธฐ์ค€์œผ๋กœ JOIN ์ œ๊ฑฐ -> ๋ฝ ๋ฒ”์œ„๋ฅผ ๋Œ€์ƒ ํ–‰ ์ž์ฒด๋กœ ํ•œ์ •
  • ๊ฐ™์€ ํŒจํ„ด์ด ๋ฝ๊ณผ ๋ฌด๊ด€ํ•œ ์กฐํšŒ 7๊ณณ(DeleteStudyPostService, CloseStudyPostService, UpdateStudyPostService, FindAppliesService, UpdateCommentService, DeleteCommentService, PostScheduler) author.id/applicant.id๋งŒ ๋น„๊ตํ•˜๋Š”๋ฐ JOIN FETCH ๋ฒ„์ „์œผ๋กœ ์กฐํšŒํ•˜๊ณ  ์žˆ์–ด ๊ธฐ๋ณธ findById()๋กœ ๊ต์ฒดํ•ด๋„ ๋™์ž‘ ๋™์ผ
  • ๋ฐ˜๋Œ€๋กœ ์‘๋‹ต ์ง๋ ฌํ™”(FindStudyPostService), ES ์ƒ‰์ธ(PostSyncKafkaConsumer), ์‹ค์ œ ์—ฐ๊ด€ ํ•„๋“œ ์‚ฌ์šฉ(TeamScheduleJpaRepository)์€ JOIN FETCH๊ฐ€ ์ •๋‹นํ•ด ์œ ์ง€
  • ์žฌ๋ฐœ ๋ฐฉ์ง€๋ฅผ ์œ„ํ•ด "์†Œ์œ ์ž ๊ฒ€์ฆ ์ „์šฉ" ๊ฒฝ๋Ÿ‰ ์กฐํšŒ ๋ฉ”์„œ๋“œ๋ฅผ ๋ณ„๋„๋กœ ๋‘๊ณ  ์žฌ์‚ฌ์šฉํ•˜๋„๋ก ์ •๋ฆฌ

Clone this wiki locally