๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ

ํ”„๋กœ์ ํŠธ

(19)
CompletableFuture๋ฅผ ํ™œ์šฉํ•ด ์™ธ๋ถ€ API ํ˜ธ์ถœ์„ ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ, ์‘๋‹ต ์‹œ๊ฐ„ 1๋ถ„ → 14์ดˆ๋กœ ๋‹จ์ถ• ๋ฌธ์ œ ์ƒํ™ฉํ”„๋กœ์ ํŠธ QA์‹œ, ์ฃผ๊ฐ„ ๋ฆฌํฌํŠธ ๊ธฐ๋Šฅ์˜ ์‘๋‹ต ์‹œ๊ฐ„์ด ์‚ฌ์šฉ์ž 1๋ช…๋‹น ์ตœ์•…์˜ ๊ฒฝ์šฐ 2๋ถ„ ์ด์ƒ, ๋Œ€์ฒด๋กœ ํ‰๊ท  1๋ถ„ ์ด์ƒ ์†Œ์š”๋˜๋Š” ๋ฌธ์ œ๊ฐ€ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.   ์ด ๋ฌธ์ œ๋ฅผ ๋ถ„์„ํ•œ ๊ฒฐ๊ณผ, DB ์ฟผ๋ฆฌ๋Š” ์‹คํ–‰ ๊ณ„ํš์ƒ eq_ref ์™€ ref๋กœ ๋น ๋ฅด๊ฒŒ ์ฒ˜๋ฆฌ๋˜๊ณ  ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.์‘๋‹ต ์‹œ๊ฐ„์ด ๊ธธ์–ด์ง„ ์ฃผ์š” ์›์ธ์€ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์—์„œ ์ตœ๋Œ€ 7๋ฒˆ์˜ ์™ธ๋ถ€ API ํ˜ธ์ถœ์„ ๋™๊ธฐ์ ์œผ๋กœ ์ฒ˜๋ฆฌํ•˜๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด์—ˆ์Šต๋‹ˆ๋‹ค.  ์•„๋ž˜ ์ฝ”๋“œ์ฒ˜๋Ÿผ, stream() ๋‚ด๋ถ€์—์„œ ์—ฐ์†์ ์ธ ์™ธ๋ถ€ API ํ˜ธ์ถœ์„ ์ฒ˜๋ฆฌํ•˜๋ฉด์„œ ์ผ์ผ ์„œ๋น„์Šค์™€ Clova AI๊ฐ€ ๋™๊ธฐ์ ์œผ๋กœ ์š”์ฒญ๊ณผ ์‘๋‹ต์„ ์ฃผ๊ณ ๋ฐ›๋Š” ๊ตฌ์กฐ๋กœ ๋™์ž‘ํ•˜๊ณ  ์žˆ์—ˆ๊ณ , ์ด๋ฅผ ๊ฐœ์„ ํ•˜๊ณ ์ž ํ–ˆ์Šต๋‹ˆ๋‹ค.Map> valuesByKey = map.values().stream() ์™ธ๋ถ€ API ํ˜ธ์ถœ, ..
์™ธ๋ถ€ API ํ˜ธ์ถœ์„ ํŠธ๋žœ์žญ์…˜์—์„œ ๋ถ„๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด FACADE ๊ณ„์ธต์„ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด, OSIV ํ™œ์„ฑํ™” ์—ฌ๋ถ€๋ฅผ ๊ณ ๋ คํ•˜์ž! ๋ฌธ์ œ ์ƒํ™ฉ: ์„œ๋กœ ๋‹ค๋ฅธ ํŠธ๋žœ์žญ์…˜์—์„œ ์—”ํ‹ฐํ‹ฐ ๋ณ€๊ฒฝ ์‹œ ๋ณ€๊ฒฝ๊ฐ์ง€๊ฐ€ ์ž‘๋™ํ•˜๋Š”๊ฐ€? ์™ธ๋ถ€ API ํ˜ธ์ถœ์„ ํŠธ๋žœ์žญ์…˜์—์„œ ๋ถ„๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด FACADE ํŒจํ„ด์„ ๋„์ž…ํ–ˆ์Šต๋‹ˆ๋‹ค.3๊ฐœ์˜ ์„œ๋น„์Šค๋ฅผ ๋ฆฌํŒฉํ† ๋งํ•˜๋ฉฐ, ํŠธ๋žœ์žญ์…˜ ๋ฒ”์œ„ ๋ฐ–์—์„œ ์™ธ๋ถ€ API๋ฅผ ํ˜ธ์ถœํ•˜๋„๋ก ์„ค๊ณ„ํ•˜์˜€๊ณ , ์ฝ”๋“œ ๊ตฌ์กฐ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์•˜์Šต๋‹ˆ๋‹ค. // ํŠธ๋žœ์žญ์…˜์—์„œ ์™ธ๋ถ€ API ํ˜ธ์ถœ์„ ๋ถ„๋ฆฌํ•˜๊ณ ์ž ๋งŒ๋“  Facade ๊ฐ์ฒดpublic class Facade { private final Service1 service1; private final Service2 service2; public ... createSomething(...) { // 1๋ฒˆ ์„œ๋น„์Šค ํŠธ๋žœ์žญ์…˜ ์‹œ์ž‘ EntityA entityA = service1.doSomething(....
OpenFeign์— INFO ๋ ˆ๋ฒจ ๋กœ๊ทธ ์ถ”๊ฐ€ํ•˜๊ธฐ (2/2): ๋กœ๊ทธ ์„ค์ •๊ณผ Configuration ๊ณ ๋ฏผ ์ €๋ฒˆ ๊ธ€์—์„œ๋Š” WireMock์„ ํ™œ์šฉํ•ด Clova AI(์™ธ๋ถ€) ์„œ๋ฒ„๋ฅผ ๋ชจํ‚นํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋‹ค๋ค˜์Šต๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด Clova ์„œ๋ฒ„๋ฅผ ํ˜ธ์ถœํ•˜์ง€ ์•Š์Œ์œผ๋กœ์จ ๋น„์šฉ ๋ฐœ์ƒ ์—†์ด, @FeignClient ์— logger-level: FULL ์„ค์ •์ด ์ž˜ ์ ์šฉ ๋˜์—ˆ๋Š”์ง€๋ฅผ ํ™•์ธํ•˜๋Š” ๊ณผ์ •์„ ์‚ดํŽด๋ดค์Šต๋‹ˆ๋‹ค.   ์ด๋ฒˆ ๊ธ€์—์„œ๋Š” INFO ๋ ˆ๋ฒจ์—์„œ Feign ๋กœ๊ทธ๋ฅผ ์ถœ๋ ฅํ•˜๋„๋ก ์ปค์Šคํ„ฐ๋งˆ์ด์ง•ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์†Œ๊ฐœํ•˜๋ ค ํ–ˆ์ง€๋งŒ, ์ด๋ฏธ ์ด๋ฅผ ๋‹ค๋ฃฌ ์ข‹์€ ๊ธ€๋“ค์ด ๋งŽ์•„ ํ•ด๋‹น ์ฃผ์ œ๋ฅผ ๊ฐ„๋‹จํžˆ ๋„˜์–ด๊ฐ€๊ณ , OpenFeign์˜ @Configuration ์„ค๊ณ„ ๊ณผ์ •์—์„œ ๊ณ ๋ฏผํ–ˆ๋˜ ์ ์„ ๊ณต์œ ํ•˜๊ณ ์ž ํ•ฉ๋‹ˆ๋‹ค.  Feign ์ปค์Šคํ„ฐ๋งˆ์ด์ง• ๊ด€๋ จ ์ข‹์€ ๊ธ€ ์šฐ์•„ํ•œ feign ์ ์šฉ๊ธฐ๋ง๋‚˜๋‹ˆ ๊ฐœ๋ฐœ์ž๋‹˜์˜ OpenFeign ์„ค๋ช… ๊ณผ Github (tistory) FeignClient Log..
OpenFeign์— INFO ๋ ˆ๋ฒจ ๋กœ๊ทธ ์ถ”๊ฐ€ํ•˜๊ธฐ (1/2): WireMock์„ ํ™œ์šฉํ•œ ์™ธ๋ถ€ ์„œ๋ฒ„ ๋ชจํ‚น ** ์ด๋ฒˆ ๊ธ€์—์„œ๋Š” ํ…Œ์ŠคํŠธ์—์„œ WireMock์„ ํ™œ์šฉํ•˜์—ฌ ์™ธ๋ถ€ ์„œ๋ฒ„๋ฅผ ๋ชจํ‚นํ•˜๋Š” ๊ณผ์ •์„ ์„ค๋ช…ํ•˜๋ฉฐ, ๋‹ค์Œ ๊ธ€์—์„œ๋Š” INFO ๋ ˆ๋ฒจ ๋กœ๊ทธ ์„ค์ • ๋ฐฉ๋ฒ•์„ ๋‹ค๋ฃฐ ์˜ˆ์ •์ž…๋‹ˆ๋‹ค. ** Clova AI์˜ ๋ฐ˜๋ณต์ ์ธ ์‘๋‹ต ์˜ค๋ฅ˜ ๋ฌธ์ œ ๊ณ ๋ฏผ ์ƒ๋‹ด ํ”Œ๋žซํผ ํ”„๋กœ์ ํŠธ๋ฅผ ์ง„ํ–‰ํ•˜๋ฉฐ ๋„ค์ด๋ฒ„ Clova AI์— ์š”์ฒญ์„ ๋ณด๋‚ด๋Š” ์ž‘์—…์„ ์ˆ˜ํ–‰ํ–ˆ์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ Clova AI๋กœ๋ถ€ํ„ฐ ์˜ค๋Š” ์‘๋‹ต์ด ๋น„์ฆˆ๋‹ˆ์Šค ์š”๊ตฌ์‚ฌํ•ญ์— ๋งž์ง€ ์•Š์•„ ๋นˆ๋ฒˆํ•˜๊ฒŒ ์˜ค๋ฅ˜๋ฅผ ๋ฐœ์ƒ์‹œ์ผฐ์Šต๋‹ˆ๋‹ค. ์ด์— ๋”ฐ๋ผ, Clova AI ๊ฐ€ ์–ด๋–ค ์‘๋‹ต์„ ์ฃผ๊ณ , ์–ด๋–ค ์˜ค๋ฅ˜๋ฅผ ์œ ๋ฐœํ•˜๋Š”์ง€ ์ •ํ™•ํžˆ ํ™•์ธํ•  ํ•„์š”๊ฐ€ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.์ด ๊ณผ์ •์—์„œ OpenFeign์˜ ๋กœ๊น… ๊ธฐ๋Šฅ์„ ํ™œ์šฉํ•˜๋ ค ํ–ˆ์ง€๋งŒ, ๊ธฐ์กด ๋ฐฉ์‹์œผ๋กœ๋Š” ๋ช‡ ๊ฐ€์ง€ ๋ถˆํŽธํ•จ์ด ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. logger-level : FULL ์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ์ด์œ 1. ์‹ค์ œ ์šด์˜ ์„œ๋ฒ„์—์„œ F..
Github Actions ์œผ๋กœ CI ํ…Œ์ŠคํŠธ ์ž๋™ํ™” ์ค‘ ๊ฒช์€ ์ด์Šˆ ์ •๋ฆฌ (Embedded Redis, Profile, Spring Rest Docs) 210๊ฐœ์˜ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ์™€ 99% ํ…Œ์ŠคํŠธ ์ปค๋ฒ„๋ฆฌ์ง€์ˆ™์†Œ ์˜ˆ์•ฝ ํ”Œ๋žซํผ์„ ๊ฐœ๋ฐœํ•˜๋ฉฐ ์ด 210์—ฌ ๊ฐœ์˜ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๊ณ , 99% ํ…Œ์ŠคํŠธ ์ปค๋ฒ„๋ฆฌ์ง€๋ฅผ ๋‹ฌ์„ฑํ–ˆ์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์ฝ”๋“œ์— ๋ณ€๊ฒฝ ์‚ฌํ•ญ์ด ์žˆ์„ ๋•Œ๋งˆ๋‹ค ์ „์ฒด ํ…Œ์ŠคํŠธ๋ฅผ ์ˆ˜๋™์œผ๋กœ ์‹คํ–‰ํ•ด์•ผ ํ–ˆ๊ณ , ์ด๋Š” ์ ์  ๋ถˆํŽธํ•œ ์ž‘์—…์ด ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ CI/CD ํˆด์ธ GitHub Actions๋ฅผ ๋„์ž…ํ•˜์—ฌ push ๋˜๋Š” pull_request๊ฐ€ ๋ฐœ์ƒํ•  ๋•Œ ์ž๋™์œผ๋กœ ํ…Œ์ŠคํŠธ๊ฐ€ ์‹คํ–‰๋˜๋„๋ก ์„ค์ •ํ–ˆ์Šต๋‹ˆ๋‹ค. GitHub Actions๋ฅผ ์„ ํƒํ•œ ์ด์œ GitHub Actions๋ฅผ ์„ ํƒํ•œ ์ด์œ ๋Š” ๋‹จ์ˆœํ•ฉ๋‹ˆ๋‹ค.Jenkins์ฒ˜๋Ÿผ ๋ณ„๋„์˜ ์„œ๋ฒ„๋ฅผ ๊ตฌ์ถ•ํ•  ํ•„์š”๊ฐ€ ์—†์œผ๋ฉฐ,๋‹จ์ˆœํžˆ .github/workflows ๋””๋ ‰ํ† ๋ฆฌ์— YAML ํŒŒ์ผ๋งŒ ์ž‘์„ฑํ•˜๋ฉด ๋ฐ”๋กœ ๋™์ž‘ํ•˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.๋˜ํ•œ Groovy์™€ ๊ฐ™์€ ์ƒˆ๋กœ์šด ๋ฌธ๋ฒ•์„..
ํŠธ๋žœ์žญ์…˜ ๋กค๋ฐฑ ์‹œ ๊ฒฐ์ œ ์ทจ์†Œ ์š”์ฒญํ•˜๊ธฐ - @TransactionalEventListener & ApplicationEventPublisher ๋ชจํ‚น ์ด์Šˆ ๊ฒฐ์ œ ํ”„๋กœ์„ธ์Šค๋ฅผ ์„ค๊ณ„ํ•˜๋ฉด์„œ, ๊ธฐ์กด์—๋Š” try-catch๋ฅผ ํ™œ์šฉํ•ด ํŠธ๋žœ์žญ์…˜ ๋‚ด๋ถ€์—์„œ ๋ฐœ์ƒํ•˜๋Š” ๋Ÿฐํƒ€์ž„ ์˜ˆ์™ธ๋ฅผ ์ฒ˜๋ฆฌํ•˜๊ณ , ๊ฒฐ์ œ ์ทจ์†Œ ์š”์ฒญ์„ ๋ณด๋ƒˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜, ์ด์— ๋Œ€ํ•œ ํ•œ๊ณ„๋ฅผ ๋Š๊ผˆ๊ณ  ํŠธ๋žœ์žญ์…˜ ๋กค๋ฐฑ ์‹œ ๊ฒฐ์ œ ์ทจ์†Œ ์š”์ฒญ์„ ๋ช…ํ™•ํ•˜๊ณ  ์ง๊ด€์ ์œผ๋กœ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด @TransactionalEventListener๋ฅผ ๋„์ž…ํ–ˆ์Šต๋‹ˆ๋‹ค.   ๊ธฐ์กด try-catch ๋ฐฉ์‹์˜ ํ•œ๊ณ„ try-catch์—์„œ๋Š” ์ฃผ๋กœ DB ์˜ˆ์™ธ(์˜ˆ: DataIntegrityViolationException)๋‚˜ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์—์„œ ๋ฐœ์ƒํ•˜๋Š” ์˜ˆ์™ธ๋ฅผ ์ฒ˜๋ฆฌํ•˜๊ณ , ๊ฒฐ์ œ ์ทจ์†Œ ์š”์ฒญ์„ ๋ณด๋ƒˆ์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ, try-catch๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์˜ˆ์™ธ๋ฅผ ์ •์ƒ์ ์ธ ํ๋ฆ„์œผ๋กœ ์ œ์–ดํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋ณด์ด๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ์ด๋Š” "ํŠธ๋žœ์žญ์…˜์ด ๋กค๋ฐฑ๋˜์—ˆ์„ ๋•Œ ๊ฒฐ์ œ ์ทจ์†Œ๋ฅผ ์ˆ˜ํ–‰ํ•œ๋‹ค"๋ผ๋Š” ์˜๋ฏธ๋ฅผ ์ •ํ™•ํžˆ ํ‘œํ˜„ํ•˜์ง€..
ISO 8601 ๊ธฐ์ค€์œผ๋กœ ํŠน์ • ๋‚ ์งœ์˜ N์›” N์ฃผ์ฐจ๋ฅผ Java 8 ๋‚ ์งœ API๋กœ ๊ตฌํ•˜๊ธฐ ISO 8601 ๋ž€ ?ISO 8601์€ ๋‚ ์งœ์™€ ์‹œ๊ฐ„์— ๊ด€๋ จ๋œ ๊ตญ์ œ ํ‘œ์ค€์œผ๋กœ์จ, ์ •์˜๋œ ๋ฐ”์— ๋”ฐ๋ฅด๋ฉด ๋งค์ฃผ์˜ ์‹œ์ž‘์ผ์€ ์›”์š”์ผ์ด ๋ฉ๋‹ˆ๋‹ค.๋˜ํ•œ, ๋งค์›”์˜ ์ฒซ ์ฃผ๋Š” ๊ณผ๋ฐ˜์ˆ˜ ์ด์ƒ์˜ ์š”์ผ์ด ํฌํ•จ๋œ ์ฃผ๊ฐ€ ๊ธฐ์ค€์ด ๋ฉ๋‹ˆ๋‹ค.  ISO 8601 ๊ธฐ์ค€์œผ๋กœ ์ฃผ์ฐจ ๊ณ„์‚ฐ ์˜ˆ์‹œ2024๋…„ 12์›” ์˜ˆ์‹œ 2024๋…„ 12์›” 30์ผ, 31์ผ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ทœ์น™์„ ๋”ฐ๋ฆ…๋‹ˆ๋‹ค. 2025๋…„ 1์›” 1~5์ผ(์ด 5์ผ)์€ 7์ผ ์ค‘ ๊ณผ๋ฐ˜์ˆ˜๋ฅผ ๋„˜์œผ๋ฏ€๋กœ 1์›” 1์ฃผ์ฐจ์ž…๋‹ˆ๋‹ค ๋”ฐ๋ผ์„œ, 2024๋…„ 12์›” 30์ผ, 31์ผ์€ 2025๋…„ 1์›” 1์ฃผ์ฐจ์— ํฌํ•จ๋ฉ๋‹ˆ๋‹ค 12์›” 2์ผ ~ 12์›” 8์ผ -> 12์›” 1์ฃผ์ฐจ12์›” 9์ผ ~ 12์›” 15์ผ -> 12์›” 2์ฃผ์ฐจ12์›” 16์ผ ~ 12์›” 22์ผ -> 12์›” 3์ฃผ์ฐจ12์›” 23์ผ ~ 12์›” 29์ผ -> 12์›” 4์ฃผ์ฐจ12์›” 30์ผ ~ ..
[ํŠธ๋Ÿฌ๋ธ”์ŠˆํŒ…] RestTemplate ๋กœ๊น… ์ค‘ 404 ์‘๋‹ต์— ๋Œ€ํ•œ FileNotFoundException ํ•ด๊ฒฐ ๊ฒฐ์ œ ์Šน์ธ POST ์š”์ฒญ ์‹œ RestTemplate ๋กœ๊ทธ์—์„œ ๋ฐœ์ƒํ•œ ์˜ค๋ฅ˜ ๊ฒฐ์ œ ๊ธฐ๋Šฅ์„ ๊ฐœ๋ฐœํ•˜๋ฉด์„œ, ๊ฒฐ์ œ ์Šน์ธ ์š”์ฒญ์„ ๋ณด๋‚ด๋Š” RestTemplate์— ํƒ€์ž„์•„์›ƒ์„ ์ ์šฉํ•˜๊ณ , ์š”์ฒญ๊ณผ ์‘๋‹ต์— ๋Œ€ํ•œ ๋กœ๊น…์„ ์ถ”๊ฐ€ํ•˜๊ณ ์ž ํ–ˆ์Šต๋‹ˆ๋‹ค.  Baeldung์˜ "RestTemplage Logging" ๊ณผ ๋ง๋‚˜๋‹ˆ ๊ฐœ๋ฐœ์ž๋‹˜์˜ ๋กœ๊น… ์„ ์ฐธ๊ณ ํ•ด์„œ RestTemplate ์— ๋กœ๊ทธ๋ฅผ ์ถ”๊ฐ€ ํ–ˆ์ง€๋งŒ ์‘๋‹ต์„ ๋ฐ›์„ ๋•Œ, FileNotFoundException ์ด ๋ฐœ์ƒํ•˜๋ฉฐ ์•„๋ž˜์™€ ๊ฐ™์€ ์Šคํƒ ํŠธ๋ ˆ์ด์Šค๋ฅผ ํ™•์ธํ–ˆ์Šต๋‹ˆ๋‹ค.java.io.FileNotFoundException: https://api.tosspayments.com/v1/payments/confirmjava.base/sun.net.www.protocol.http.HttpURLConnection..