2025๋…„ 3์›” 15์ผยท5๋ถ„ ์ฝ๊ธฐ

API์šฉ Go ์ปจํ…์ŠคํŠธ ํƒ€์ž„์•„์›ƒ: HTTP ํ•ธ๋“ค๋Ÿฌ์—์„œ SQL๊นŒ์ง€

API์—์„œ Go ์ปจํ…์ŠคํŠธ ํƒ€์ž„์•„์›ƒ์€ HTTP ํ•ธ๋“ค๋Ÿฌ์—์„œ SQL ํ˜ธ์ถœ๋กœ ๊ธฐํ•œ์„ ์ „๋‹ฌํ•ด ๋ฉˆ์ถฐ๋ฒ„๋ฆฌ๋Š” ์š”์ฒญ์„ ๋ง‰๊ณ  ๋ถ€ํ•˜ ์‹œ์—๋„ ์„œ๋น„์Šค๋ฅผ ์•ˆ์ •์ ์œผ๋กœ ์œ ์ง€ํ•˜๋„๋ก ๋•์Šต๋‹ˆ๋‹ค.

API์šฉ Go ์ปจํ…์ŠคํŠธ ํƒ€์ž„์•„์›ƒ: HTTP ํ•ธ๋“ค๋Ÿฌ์—์„œ SQL๊นŒ์ง€

์š”์ฒญ์ด ๋ฉˆ์ถ”๋Š” ์ด์œ (๊ทธ๋ฆฌ๊ณ  ๋ถ€ํ•˜ ์‹œ ์™œ ํ•ด๋กœ์šด๊ฐ€)\n\n์š”์ฒญ์ด "๋ฉˆ์ท„๋‹ค(stuck)"๋Š” ๊ฒƒ์€ ๋ฐ˜ํ™˜ํ•˜์ง€ ์•Š๋Š” ๋ฌด์–ธ๊ฐ€๋ฅผ ๊ธฐ๋‹ค๋ฆฌ๊ณ  ์žˆ์„ ๋•Œ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค: ๋А๋ฆฐ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ฟผ๋ฆฌ, ํ’€์—์„œ ๋ง‰ํžŒ ์—ฐ๊ฒฐ, DNS ๋ฌธ์ œ, ๋˜๋Š” ํ˜ธ์ถœ์€ ๋ฐ›์•˜์ง€๋งŒ ์‘๋‹ต์„ ํ•˜์ง€ ์•Š๋Š” ์ƒ์œ„ ์„œ๋น„์Šค ๋“ฑ์ž…๋‹ˆ๋‹ค.\n\n์ฆ์ƒ์€ ๋‹จ์ˆœํ•ด ๋ณด์ž…๋‹ˆ๋‹ค: ์ผ๋ถ€ ์š”์ฒญ์ด ์˜์›ํžˆ ๊ฑธ๋ฆฌ๊ณ , ๊ทธ ๋’ค๋กœ ์ ์  ๋” ๋งŽ์€ ์š”์ฒญ์ด ์Œ“์ž…๋‹ˆ๋‹ค. ๋ฉ”๋ชจ๋ฆฌ๊ฐ€ ์ฆ๊ฐ€ํ•˜๊ณ  ๊ณ ๋ฃจํ‹ด ์ˆ˜๊ฐ€ ๋Š˜๋ฉฐ, ์‰ฝ๊ฒŒ ๋น„์›Œ์ง€์ง€ ์•Š๋Š” ์—ด๋ฆฐ ์—ฐ๊ฒฐ ๋Œ€๊ธฐ์—ด์„ ๋ณด๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.\n\n๋ถ€ํ•˜๊ฐ€ ๊ฑธ๋ฆฌ๋ฉด ๋ฉˆ์ถ˜ ์š”์ฒญ์€ ์ด์ค‘์œผ๋กœ ํ•ด๋ฅผ ๋ผ์นฉ๋‹ˆ๋‹ค. ์ž‘์—…์ž๋ฅผ ๋ฌถ์–ด๋‘๊ณ  ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์—ฐ๊ฒฐ์ด๋‚˜ ๋ฝ ๊ฐ™์€ ๊ท€ํ•œ ์ž์›์„ ์ ์œ ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ ๋•Œ๋ฌธ์— ๋ณดํ†ต ๋น ๋ฅธ ์š”์ฒญ๋„ ๋А๋ ค์ง€๊ณ , ๊ฒน์นจ์ด ์ƒ๊ธฐ๋ฉฐ ๊ธฐ๋‹ค๋ฆผ์ด ๋” ๋Š˜์–ด๋‚ฉ๋‹ˆ๋‹ค.\n\n์žฌ์‹œ๋„์™€ ํŠธ๋ž˜ํ”ฝ ์ŠคํŒŒ์ดํฌ๋Š” ์ด ์•…์ˆœํ™˜์„ ์•…ํ™”์‹œํ‚ต๋‹ˆ๋‹ค. ํด๋ผ์ด์–ธํŠธ๊ฐ€ ํƒ€์ž„์•„์›ƒ๋˜์–ด ์žฌ์‹œ๋„ํ•˜๋Š” ๋™์•ˆ ์›๋ž˜ ์š”์ฒญ์€ ์—ฌ์ „ํžˆ ์‹คํ–‰ ์ค‘์ผ ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ๊ฐ™์€ ์ž‘์—…์— ๋Œ€ํ•ด ๋‘ ๋ฐฐ ๋น„์šฉ์„ ์ง€๋ถˆํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ์งง์€ ์ง€์—ฐ ๋™์•ˆ ์—ฌ๋Ÿฌ ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์žฌ์‹œ๋„ํ•˜๋ฉด ํ‰๊ท  ํŠธ๋ž˜ํ”ฝ์ด ๊ดœ์ฐฎ๋”๋ผ๋„ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ฅผ ๊ณผ๋ถ€ํ•˜์‹œํ‚ค๊ฑฐ๋‚˜ ์—ฐ๊ฒฐ ํ•œ๋„์— ๋„๋‹ฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.\n\nํƒ€์ž„์•„์›ƒ์€ ๋‹จ์ˆœํ•œ ์•ฝ์†์ž…๋‹ˆ๋‹ค: "์šฐ๋ฆฌ๋Š” X ์ด์ƒ ๊ธฐ๋‹ค๋ฆฌ์ง€ ์•Š๊ฒ ๋‹ค." ์ด๋Š” ๋น ๋ฅด๊ฒŒ ์‹คํŒจ(fail fast)ํ•˜๊ณ  ์ž์›์„ ํ•ด์ œํ•˜๋Š” ๋ฐ ๋„์›€์ด ๋˜์ง€๋งŒ ์ž‘์—…์„ ๋” ๋นจ๋ฆฌ ๋๋‚˜๊ฒŒ ํ•˜์ง€๋Š” ์•Š์Šต๋‹ˆ๋‹ค.\n\n๋˜ํ•œ ์ž‘์—…์ด ์ฆ‰์‹œ ์ค‘๋‹จ๋œ๋‹ค๋Š” ๋ณด์žฅ๋„ ์•„๋‹™๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋Š” ๊ณ„์† ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๊ณ , ์ƒ์œ„ ์„œ๋น„์Šค๋Š” ์ทจ์†Œ๋ฅผ ๋ฌด์‹œํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์ฝ”๋“œ ์ž์ฒด๊ฐ€ ์ทจ์†Œ๊ฐ€ ๋ฐœ์ƒํ–ˆ์„ ๋•Œ ์•ˆ์ „ํ•˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.\n\nํƒ€์ž„์•„์›ƒ์ด ๋ณด์žฅํ•˜๋Š” ๊ฒƒ์€ ํ•ธ๋“ค๋Ÿฌ๊ฐ€ ๊ธฐ๋‹ค๋ฆผ์„ ๋ฉˆ์ถ”๊ณ  ๋ช…ํ™•ํ•œ ์˜ค๋ฅ˜๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋ฉฐ ๋ณด์œ ํ•œ ์ž์›์„ ํ•ด์ œํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์ ์ž…๋‹ˆ๋‹ค. ์ด ์ œํ•œ๋œ ๋Œ€๊ธฐ๋Š” ๋ช‡ ๋ฒˆ์˜ ๋А๋ฆฐ ํ˜ธ์ถœ์ด ์ „์ฒด ์žฅ์• ๋กœ ๋ฒˆ์ง€๋Š” ๊ฒƒ์„ ๋ง‰์•„์ค๋‹ˆ๋‹ค.\n\nGo ์ปจํ…์ŠคํŠธ ํƒ€์ž„์•„์›ƒ์˜ ๋ชฉํ‘œ๋Š” ์—์ง€์—์„œ ๊ฐ€์žฅ ๊นŠ์€ ํ˜ธ์ถœ๊นŒ์ง€ ํ•˜๋‚˜์˜ ๊ณต์œ ๋œ ๋ฐ๋“œ๋ผ์ธ์„ ๊ฐ–๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. HTTP ๊ฒฝ๊ณ„์—์„œ ํ•œ ๋ฒˆ ์„ค์ •ํ•˜๊ณ  ๋™์ผํ•œ ์ปจํ…์ŠคํŠธ๋ฅผ ์„œ๋น„์Šค ์ฝ”๋“œ ์ „๋ฐ˜์— ์ „๋‹ฌํ•˜๋ฉฐ database/sql ํ˜ธ์ถœ์—๋„ ์‚ฌ์šฉํ•˜๋ฉด ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋„ ์–ธ์ œ ๊ธฐ๋‹ค๋ฆผ์„ ๋ฉˆ์ถฐ์•ผ ํ•˜๋Š”์ง€ ์•Œ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.\n\n## Go์˜ ์ปจํ…์ŠคํŠธ๋ฅผ ์‰ฌ์šด ์šฉ์–ด๋กœ\n\ncontext.Context๋Š” ํ˜„์žฌ ๋ฌด์Šจ ์ผ์ด ์ง„ํ–‰ ์ค‘์ธ์ง€ ์„ค๋ช…ํ•˜๊ธฐ ์œ„ํ•ด ์ฝ”๋“œ ์ „์ฒด์— ์ „๋‹ฌํ•˜๋Š” ์ž‘์€ ๊ฐ์ฒด์ž…๋‹ˆ๋‹ค. "์ด ์š”์ฒญ์ด ์•„์ง ์œ ํšจํ•œ๊ฐ€?", "์–ธ์ œ ํฌ๊ธฐํ•ด์•ผ ํ•˜๋‚˜?", "์š”์ฒญ ๋ฒ”์œ„์˜ ์–ด๋–ค ๊ฐ’์ด ์ด ์ž‘์—…๊ณผ ํ•จ๊ป˜ ๊ฐ€์•ผ ํ•˜๋‚˜?" ๊ฐ™์€ ์งˆ๋ฌธ์— ๋‹ตํ•ฉ๋‹ˆ๋‹ค.\n\nํ•ต์‹ฌ ์žฅ์ ์€ ์‹œ์Šคํ…œ์˜ ๊ฐ€์žฅ์ž๋ฆฌ(HTTP ํ•ธ๋“ค๋Ÿฌ)์—์„œ ๋‚ด๋ฆฐ ํ•œ ๋ฒˆ์˜ ๊ฒฐ์ •์ด ๋™์ผํ•œ ์ปจํ…์ŠคํŠธ๋ฅผ ์ „๋‹ฌํ•˜๋ฉด ๋ชจ๋“  ํ•˜์œ„ ๋‹จ๊ณ„๋“ค์„ ๋ณดํ˜ธํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์ ์ž…๋‹ˆ๋‹ค.\n\n### ์ปจํ…์ŠคํŠธ๊ฐ€ ๋‹ด๋Š” ๊ฒƒ\n\n์ปจํ…์ŠคํŠธ๋Š” ๋น„์ฆˆ๋‹ˆ์Šค ๋ฐ์ดํ„ฐ๋ฅผ ์œ„ํ•œ ์žฅ์†Œ๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค. ์ œ์–ด ์‹ ํ˜ธ์™€ ์†Œ๋Ÿ‰์˜ ์š”์ฒญ ๋ฒ”์œ„ ์ •๋ณด: ์ทจ์†Œ, ๋ฐ๋“œ๋ผ์ธ/ํƒ€์ž„์•„์›ƒ, ๋กœ๊ทธ์šฉ ์š”์ฒญ ID ๊ฐ™์€ ์ž‘์€ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ๋ฅผ ์œ„ํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค.\n\nํƒ€์ž„์•„์›ƒ๊ณผ ์ทจ์†Œ์˜ ์ฐจ์ด๋Š” ๊ฐ„๋‹จํ•ฉ๋‹ˆ๋‹ค: ํƒ€์ž„์•„์›ƒ์€ ์ทจ์†Œ์˜ ํ•œ ์ด์œ ์ž…๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด 2์ดˆ ํƒ€์ž„์•„์›ƒ์„ ์„ค์ •ํ•˜๋ฉด 2์ดˆ๊ฐ€ ์ง€๋‚˜๋ฉด ์ปจํ…์ŠคํŠธ๋Š” ์ทจ์†Œ๋ฉ๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์‚ฌ์šฉ์ž๊ฐ€ ํƒญ์„ ๋‹ซ๊ฑฐ๋‚˜ ๋กœ๋“œ๋ฐธ๋Ÿฐ์„œ๊ฐ€ ์—ฐ๊ฒฐ์„ ๋Š๊ฑฐ๋‚˜ ์ฝ”๋“œ๊ฐ€ ์š”์ฒญ์„ ์ค‘๋‹จํ•˜๊ธฐ๋กœ ๊ฒฐ์ •ํ•˜๋ฉด ์ปจํ…์ŠคํŠธ๋Š” ๋” ์ผ์ฐ ์ทจ์†Œ๋  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.\n\n์ปจํ…์ŠคํŠธ๋Š” ๋ณดํ†ต ์ฒซ ๋ฒˆ์งธ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ๋ช…์‹œ์ ์œผ๋กœ ์ „๋‹ฌ๋˜์–ด ํ•จ์ˆ˜ ํ˜ธ์ถœ์„ ๋”ฐ๋ผ ํ๋ฆ…๋‹ˆ๋‹ค: func DoThing(ctx context.Context, ...). ํ˜ธ์ถœ ์ง€์ ์— ๊ณ„์† ๋ณด์ด๊ธฐ ๋•Œ๋ฌธ์— "์žŠ์–ด๋ฒ„๋ฆฌ๊ธฐ" ์–ด๋ ต์Šต๋‹ˆ๋‹ค.\n\n๋ฐ๋“œ๋ผ์ธ์ด ๋งŒ๋ฃŒ๋˜๋ฉด ๊ทธ ์ปจํ…์ŠคํŠธ๋ฅผ ๊ด€์ฐฐํ•˜๋Š” ๊ฒƒ์€ ๋น ๋ฅด๊ฒŒ ๋ฉˆ์ถฐ์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด QueryContext๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ฟผ๋ฆฌ๋Š” context deadline exceeded ๊ฐ™์€ ์˜ค๋ฅ˜์™€ ํ•จ๊ป˜ ์กฐ๊ธฐ์— ๋ฐ˜ํ™˜ํ•ด์•ผ ํ•˜๊ณ , ํ•ธ๋“ค๋Ÿฌ๋Š” ์„œ๋ฒ„๊ฐ€ ์ž‘์—…์ž๋ฅผ ๋ชจ๋‘ ์†Œ์ง„ํ•  ๋•Œ๊นŒ์ง€ ๋งค๋‹ฌ๋ฆฌ์ง€ ์•Š๊ณ  ํƒ€์ž„์•„์›ƒ์œผ๋กœ ์‘๋‹ตํ•  ์ˆ˜ ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.\n\n์ข‹์€ ์‚ฌ๊ณ  ๋ชจ๋ธ์€ ์ด๋ ‡์Šต๋‹ˆ๋‹ค: ํ•˜๋‚˜์˜ ์š”์ฒญ, ํ•˜๋‚˜์˜ ์ปจํ…์ŠคํŠธ, ์–ด๋””๋“  ์ „๋‹ฌํ•˜์„ธ์š”. ์š”์ฒญ์ด ์ฃฝ์œผ๋ฉด ์ž‘์—…๋„ ํ•จ๊ป˜ ๋ฉˆ์ถฐ์•ผ ํ•ฉ๋‹ˆ๋‹ค.\n\n## HTTP ๊ฒฝ๊ณ„์—์„œ ๋ช…ํ™•ํ•œ ๋ฐ๋“œ๋ผ์ธ ์„ค์ •ํ•˜๊ธฐ\n\n์—”๋“œํˆฌ์—”๋“œ ํƒ€์ž„์•„์›ƒ์„ ์ž‘๋™์‹œํ‚ค๋ ค๋ฉด ์‹œ๊ณ„๊ฐ€ ์–ด๋””์„œ ์‹œ์ž‘๋˜๋Š”์ง€ ๊ฒฐ์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๊ฐ€์žฅ ์•ˆ์ „ํ•œ ์œ„์น˜๋Š” HTTP ์—์ง€ ๋ฐ”๋กœ ์ง€์ ์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋ฉด ๋ชจ๋“  ํ•˜์œ„ ํ˜ธ์ถœ(๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง, SQL, ๋‹ค๋ฅธ ์„œ๋น„์Šค)์ด ๋™์ผํ•œ ๋ฐ๋“œ๋ผ์ธ์„ ์ƒ์†๋ฐ›์Šต๋‹ˆ๋‹ค.\n\n๊ทธ ๋ฐ๋“œ๋ผ์ธ์€ ์—ฌ๋Ÿฌ ๊ณณ์—์„œ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์„œ๋ฒ„ ์ˆ˜์ค€ ํƒ€์ž„์•„์›ƒ์€ ์ข‹์€ ๊ธฐ๋ณธ ๋ณดํ˜ธ๋ง‰์ด๊ณ  ๋А๋ฆฐ ํด๋ผ์ด์–ธํŠธ๋กœ๋ถ€ํ„ฐ ๋ณดํ˜ธํ•ด ์ค๋‹ˆ๋‹ค. ๋ฏธ๋“ค์›จ์–ด๋Š” ๋ผ์šฐํŠธ ๊ทธ๋ฃน ์ „๋ฐ˜์— ์ผ๊ด€์„ฑ์„ ์ฃผ๊ธฐ์— ํ›Œ๋ฅญํ•ฉ๋‹ˆ๋‹ค. ํ•ธ๋“ค๋Ÿฌ ๋‚ด๋ถ€์—์„œ ์„ค์ •ํ•˜๋Š” ๊ฒƒ๋„ ๋ช…ํ™•ํ•˜๊ณ  ๊ตญ์†Œ์ ์ธ ์„ค์ •์ด ํ•„์š”ํ•  ๋•Œ ๊ดœ์ฐฎ์Šต๋‹ˆ๋‹ค.\n\n๋Œ€๋ถ€๋ถ„์˜ API์—์„œ๋Š” ๋ฏธ๋“ค์›จ์–ด๋‚˜ ํ•ธ๋“ค๋Ÿฌ์—์„œ์˜ ์š”์ฒญ๋ณ„ ํƒ€์ž„์•„์›ƒ์ด ๊ฐ€์žฅ ์ดํ•ดํ•˜๊ธฐ ์‰ฝ์Šต๋‹ˆ๋‹ค. ํ˜„์‹ค์ ์œผ๋กœ ์„ค์ •ํ•˜์„ธ์š”: ์‚ฌ์šฉ์ž๋Š” ๋А๋ฆฌ๊ฒŒ ๋งค๋‹ฌ๋ฆฌ๋Š” ๊ฒƒ๋ณด๋‹ค ๋น ๋ฅด๊ณ  ๋ช…ํ™•ํ•œ ์‹คํŒจ๋ฅผ ์„ ํ˜ธํ•ฉ๋‹ˆ๋‹ค. ๋งŽ์€ ํŒ€์€ ์ฝ๊ธฐ ์ž‘์—…์— ๋Œ€ํ•ด ์งง์€ ์˜ˆ์‚ฐ(์˜ˆ: 1โ€“2์ดˆ)์„, ์“ฐ๊ธฐ์—๋Š” ์ข€ ๋” ๊ธด ์˜ˆ์‚ฐ(์˜ˆ: 3โ€“10์ดˆ)์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.\n\n๊ฐ„๋‹จํ•œ ํ•ธ๋“ค๋Ÿฌ ํŒจํ„ด์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:\n\ngo\nfunc (s *Server) getReport(w http.ResponseWriter, r *http.Request) {\n ctx, cancel := context.WithTimeout(r.Context(), 2*time.Second)\n defer cancel()\n\n report, err := s.reports.Generate(ctx, r.URL.Query().Get(\"id\"))\n if err != nil {\n http.Error(w, err.Error(), http.StatusGatewayTimeout)\n return\n }\n\n json.NewEncoder(w).Encode(report)\n}\n\n\n์ด ํŒจํ„ด์„ ํšจ๊ณผ์ ์œผ๋กœ ์œ ์ง€ํ•˜๋Š” ๋‘ ๊ฐ€์ง€ ๊ทœ์น™:\n\n- ํ•ญ์ƒ cancel()์„ ํ˜ธ์ถœํ•ด ํƒ€์ด๋จธ์™€ ์ž์›์ด ๋น ๋ฅด๊ฒŒ ํ•ด์ œ๋˜๋„๋ก ํ•˜์„ธ์š”.\n- ํ•ธ๋“ค๋Ÿฌ ์•ˆ์—์„œ ์š”์ฒญ ์ปจํ…์ŠคํŠธ๋ฅผ context.Background()๋‚˜ context.TODO()๋กœ ๋Œ€์ฒดํ•˜์ง€ ๋งˆ์„ธ์š”. ๊ทธ๋Ÿฌ๋ฉด ์ฒด์ธ์ด ๋Š๊ฒจ์„œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ํ˜ธ์ถœ๊ณผ ์™ธ๋ถ€ ์š”์ฒญ์ด ํด๋ผ์ด์–ธํŠธ๊ฐ€ ๋– ๋‚œ ๋’ค์—๋„ ์˜์›ํžˆ ์‹คํ–‰๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.\n\n## ์ฝ”๋“œ๋ฒ ์ด์Šค ์ „๋ฐ˜์— ์ปจํ…์ŠคํŠธ ์ „ํŒŒํ•˜๊ธฐ\n\nHTTP ๊ฒฝ๊ณ„์—์„œ ๋ฐ๋“œ๋ผ์ธ์„ ์„ค์ •ํ•œ ํ›„ ์‹ค์ œ ์ž‘์—…์€ ๊ทธ ๋™์ผํ•œ ๋ฐ๋“œ๋ผ์ธ์ด ๋ธ”๋กœํ‚นํ•  ์ˆ˜ ์žˆ๋Š” ๋ชจ๋“  ๊ณ„์ธต์— ๋„๋‹ฌํ•˜๋„๋ก ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์•„์ด๋””์–ด๋Š” ํ•˜๋‚˜์˜ ์‹œ๊ณ„๊ฐ€ ํ•ธ๋“ค๋Ÿฌ, ์„œ๋น„์Šค ์ฝ”๋“œ, ๋„คํŠธ์›Œํฌ๋‚˜ ๋””์Šคํฌ์— ์ ‘๊ทผํ•˜๋Š” ๋ชจ๋“  ๊ณณ์—์„œ ๊ณต์œ ๋˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.\n\n์ผ๊ด€์„ฑ์„ ์œ ์ง€ํ•˜๋Š” ๊ฐ„๋‹จํ•œ ๊ทœ์น™: ๊ธฐ๋‹ค๋ฆด ์ˆ˜ ์žˆ๋Š” ๋ชจ๋“  ํ•จ์ˆ˜๋Š” context.Context๋ฅผ ๋ฐ›์•„์•ผ ํ•˜๊ณ , ์ด๊ฒƒ์ด ์ฒซ ๋ฒˆ์งธ ์ธ์ž๊ฐ€ ๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ํ˜ธ์ถœ ์ง€์ ์—์„œ ๋ช…ํ™•ํ•ด์ง€๊ณ  ์Šต๊ด€์ด ๋ฉ๋‹ˆ๋‹ค.\n\n### ์‹ค์šฉ์ ์ธ ์‹œ๊ทธ๋‹ˆ์ฒ˜ ํŒจํ„ด\n\n์„œ๋น„์Šค์™€ ๋ ˆํฌ์ง€ํ† ๋ฆฌ์—๋Š” DoThing(ctx context.Context, ...) ๊ฐ™์€ ์‹œ๊ทธ๋‹ˆ์ฒ˜๋ฅผ ์„ ํ˜ธํ•˜์„ธ์š”. ์ปจํ…์ŠคํŠธ๋ฅผ ๊ตฌ์กฐ์ฒด ์•ˆ์— ์ˆจ๊ธฐ๊ฑฐ๋‚˜ ํ•˜์œ„ ๋ ˆ์ด์–ด์—์„œ context.Background()๋กœ ๋‹ค์‹œ ๋งŒ๋“ค์ง€ ๋งˆ์„ธ์š”. ๊ทธ๋Ÿฌ๋ฉด ํ˜ธ์ถœ์ž์˜ ๋ฐ๋“œ๋ผ์ธ์ด ์กฐ์šฉํžˆ ์‚ฌ๋ผ์ง‘๋‹ˆ๋‹ค.\n\ngo\nfunc (h *Handler) CreateOrder(w http.ResponseWriter, r *http.Request) {\n ctx := r.Context()\n\n if err := h.svc.CreateOrder(ctx, r.Body); err != nil {\n // map context errors to a clear client response elsewhere\n http.Error(w, err.Error(), http.StatusRequestTimeout)\n return\n }\n}\n\nfunc (s *Service) CreateOrder(ctx context.Context, body io.Reader) error {\n // parsing or validation can still respect cancellation\n select {\n case <-ctx.Done():\n return ctx.Err()\n default:\n }\n\n return s.repo.InsertOrder(ctx, /* data */)\n}\n\n\n### ์กฐ๊ธฐ ์ข…๋ฃŒ๋ฅผ ๊น”๋”ํ•˜๊ฒŒ ์ฒ˜๋ฆฌํ•˜๊ธฐ\n\nctx.Done()๋ฅผ ์ •์ƒ์ ์ธ ์ œ์–ด ๊ฒฝ๋กœ๋กœ ์ทจ๊ธ‰ํ•˜์„ธ์š”. ๋„์›€์ด ๋˜๋Š” ๋‘ ๊ฐ€์ง€ ์Šต๊ด€:\n\n- ๋น„์šฉ์ด ํฐ ์ž‘์—…์„ ์‹œ์ž‘ํ•˜๊ธฐ ์ „๊ณผ ๊ธด ๋ฃจํ”„ ํ›„์— ctx.Err()๋ฅผ ํ™•์ธํ•˜์„ธ์š”.\n- ctx.Err()๋ฅผ ์œ„์ชฝ์œผ๋กœ ๋ณ€๊ฒฝ ์—†์ด ๋ฐ˜ํ™˜ํ•ด ํ•ธ๋“ค๋Ÿฌ๊ฐ€ ๋น ๋ฅด๊ฒŒ ์‘๋‹ตํ•˜๊ณ  ์ž์› ๋‚ญ๋น„๋ฅผ ๋ฉˆ์ถ”๊ฒŒ ํ•˜์„ธ์š”.\n\n๋ชจ๋“  ๋ ˆ์ด์–ด๊ฐ€ ๋™์ผํ•œ ctx๋ฅผ ์ „๋‹ฌํ•˜๋ฉด ํ•˜๋‚˜์˜ ํƒ€์ž„์•„์›ƒ์œผ๋กœ ํŒŒ์‹ฑ, ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง, ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๋Œ€๊ธฐ๊ฐ€ ํ•œ ๋ฒˆ์— ์ฐจ๋‹จ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.\n\n## database/sql ์ฟผ๋ฆฌ์— ๋ฐ๋“œ๋ผ์ธ ์ ์šฉํ•˜๊ธฐ\n\nHTTP ํ•ธ๋“ค๋Ÿฌ์— ๋ฐ๋“œ๋ผ์ธ์ด ์„ค์ •๋˜์—ˆ๋‹ค๋ฉด ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ž‘์—…์ด ์‹ค์ œ๋กœ ๊ทธ ์‹ ํ˜ธ๋ฅผ ๋“ฃ๋Š”์ง€ ํ™•์ธํ•˜์„ธ์š”. database/sql์—์„œ๋Š” ๋งค๋ฒˆ ์ปจํ…์ŠคํŠธ ์ธ์‹ ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. ์ปจํ…์ŠคํŠธ ์—†์ด Query()๋‚˜ Exec()๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด ํด๋ผ์ด์–ธํŠธ๊ฐ€ ํฌ๊ธฐํ•œ ๋’ค์—๋„ API๊ฐ€ ๋А๋ฆฐ ์ฟผ๋ฆฌ๋ฅผ ๊ณ„์† ๊ธฐ๋‹ค๋ฆด ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.\n\n์ผ๊ด€๋˜๊ฒŒ ์‚ฌ์šฉํ•˜์„ธ์š”: db.QueryContext, db.QueryRowContext, db.ExecContext, db.PrepareContext(๊ทธ๋ฆฌ๊ณ  ๋ฐ˜ํ™˜๋œ statement์—์„œ QueryContext/ExecContext).\n\ngo\nfunc (s *Store) GetUser(ctx context.Context, id int64) (*User, error) {\n row := s.db.QueryRowContext(ctx,\n `SELECT id, email FROM users WHERE id = $1`, id,\n )\n var u User\n if err := row.Scan(&u.ID, &u.Email); err != nil {\n return nil, err\n }\n return &u, nil\n}\n\nfunc (s *Store) UpdateEmail(ctx context.Context, id int64, email string) error {\n _, err := s.db.ExecContext(ctx,\n `UPDATE users SET email = $1 WHERE id = $2`, email, id,\n )\n return err\n}\n\n\n๋†“์น˜๊ธฐ ์‰ฌ์šด ๋‘ ๊ฐ€์ง€๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.\n\n์ฒซ์งธ, SQL ๋“œ๋ผ์ด๋ฒ„๊ฐ€ ์ปจํ…์ŠคํŠธ ์ทจ์†Œ๋ฅผ ์กด์ค‘ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋งŽ์€ ๋“œ๋ผ์ด๋ฒ„๊ฐ€ ๊ทธ๋ ‡์ง€๋งŒ, ์Šคํƒ์—์„œ ๋А๋ฆฐ ์ฟผ๋ฆฌ๋ฅผ ์˜๋„์ ์œผ๋กœ ์‹คํ–‰ํ•ด ๋ฐ๋“œ๋ผ์ธ ์ดˆ๊ณผ ์‹œ ๋น ๋ฅด๊ฒŒ ์ทจ์†Œ๋˜๋Š”์ง€ ํ™•์ธํ•˜์„ธ์š”.\n\n๋‘˜์งธ, ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ธก ํƒ€์ž„์•„์›ƒ์„ ๋ฐฑ์Šคํ†ฑ์œผ๋กœ ๊ณ ๋ คํ•˜์„ธ์š”. ์˜ˆ๋ฅผ ๋“ค์–ด Postgres๋Š” ์ข…์ข… statement timeout์œผ๋กœ ๋ถˆ๋ฆฌ๋Š” ๋ฌธ์žฅ๋ณ„ ์ œํ•œ์„ ์ ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” ์•ฑ ๋ฒ„๊ทธ๋กœ ์ปจํ…์ŠคํŠธ ์ „๋‹ฌ์ด ๋ˆ„๋ฝ๋œ ๊ฒฝ์šฐ์—๋„ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ฅผ ๋ณดํ˜ธํ•ฉ๋‹ˆ๋‹ค.\n\n์ž‘์—…์ด ํƒ€์ž„์•„์›ƒ ๋•Œ๋ฌธ์— ์ค‘๋‹จ๋˜๋ฉด ์ผ๋ฐ˜ SQL ์˜ค๋ฅ˜์™€ ๋‹ค๋ฅด๊ฒŒ ์ฒ˜๋ฆฌํ•˜์„ธ์š”. errors.Is(err, context.DeadlineExceeded)์™€ errors.Is(err, context.Canceled)๋ฅผ ํ™•์ธํ•˜๊ณ (๊ฐ€๋Šฅํ•˜๋ฉด) 504 ๊ฐ™์€ ๋ช…ํ™•ํ•œ ์‘๋‹ต์œผ๋กœ ๋งคํ•‘ํ•˜์„ธ์š”. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ๋ฌธ์ œ๋ฅผ "๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๊ฐ€ ๋ง๊ฐ€์กŒ๋‹ค"๊ณ  ์ž˜๋ชป ์ฒ˜๋ฆฌํ•˜์ง€ ์•Š๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. AppMaster์ฒ˜๋Ÿผ Go ๋ฐฑ์—”๋“œ๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๊ฒฝ์šฐ์—๋„ ์ด ์˜ค๋ฅ˜ ๊ฒฝ๋กœ๋ฅผ ๊ตฌ๋ถ„ํ•˜๋ฉด ๋กœ๊ทธ์™€ ์žฌ์‹œ๋„ ์ •์ฑ…์„ ์ดํ•ดํ•˜๊ธฐ ์‰ฌ์›Œ์ง‘๋‹ˆ๋‹ค.\n\n## ํ•˜์œ„ ํ˜ธ์ถœ: HTTP ํด๋ผ์ด์–ธํŠธ, ์บ์‹œ, ๊ธฐํƒ€ ์„œ๋น„์Šค\n\nํ•ธ๋“ค๋Ÿฌ์™€ SQL ์ฟผ๋ฆฌ๊ฐ€ ์ปจํ…์ŠคํŠธ๋ฅผ ์กด์ค‘ํ•˜๋”๋ผ๋„ ํ•˜์œ„ ํ˜ธ์ถœ์ด ์˜์›ํžˆ ๊ธฐ๋‹ค๋ฆฌ๋ฉด ์š”์ฒญ์ด ์—ฌ์ „ํžˆ ๊ฑธ๋ฆด ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ถ€ํ•˜๊ฐ€ ๊ฑธ๋ฆฌ๋ฉด ๋ช‡ ๊ฐ€์ง€ ๊ฑธ๋ฆฐ ๊ณ ๋ฃจํ‹ด์ด ์Œ“์—ฌ ์—ฐ๊ฒฐ ํ’€์ด ๊ณ ๊ฐˆ๋˜๊ณ  ์ž‘์€ ์ง€์—ฐ์ด ์ „์ฒด ์ •์ง€๋กœ ๋ฒˆ์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ•ด๊ฒฐ์ฑ…์€ ์ผ๊ด€๋œ ์ „ํŒŒ์™€ ๋ช…ํ™•ํ•œ ๋ฐฑ์Šคํ†ฑ์ž…๋‹ˆ๋‹ค.\n\n### ์•„์›ƒ๋ฐ”์šด๋“œ HTTP\n\n๋‹ค๋ฅธ API๋ฅผ ํ˜ธ์ถœํ•  ๋•Œ ๋™์ผํ•œ ์ปจํ…์ŠคํŠธ๋กœ ์š”์ฒญ์„ ์ƒ์„ฑํ•˜๋ฉด ๋ฐ๋“œ๋ผ์ธ๊ณผ ์ทจ์†Œ๊ฐ€ ์ž๋™์œผ๋กœ ์ „๋‹ฌ๋ฉ๋‹ˆ๋‹ค.\n\ngo\nreq, err := http.NewRequestWithContext(ctx, "GET", url, nil)\nif err != nil { /* handle */ }\nresp, err := httpClient.Do(req)\n\n\n์ปจํ…์ŠคํŠธ๋งŒ ๋ฏฟ์ง€ ๋งˆ์„ธ์š”. ์ฝ”๋“œ๊ฐ€ ์‹ค์ˆ˜๋กœ background ์ปจํ…์ŠคํŠธ๋ฅผ ์‚ฌ์šฉํ•˜๊ฑฐ๋‚˜ DNS/TLS/์œ ํœด ์—ฐ๊ฒฐ์ด ๋ฉˆ์ถœ ๊ฒฝ์šฐ์— ๋Œ€๋น„ํ•ด HTTP ํด๋ผ์ด์–ธํŠธ์™€ ํŠธ๋žœ์ŠคํฌํŠธ๋ฅผ ๊ตฌ์„ฑํ•˜์„ธ์š”. http.Client.Timeout์„ ์ „์ฒด ํ˜ธ์ถœ์˜ ์ƒํ•œ์œผ๋กœ ์„ค์ •ํ•˜๊ณ , ๋‹ค์ด์–ผ/ํ•ธ๋“œ์…ฐ์ดํฌ/์‘๋‹ต ํ—ค๋” ํƒ€์ž„์•„์›ƒ์„ ์„ค์ •ํ•˜๋ฉฐ ์š”์ฒญ๋งˆ๋‹ค ์ƒˆ ํด๋ผ์ด์–ธํŠธ๋ฅผ ๋งŒ๋“ค์ง€ ๋ง๊ณ  ์žฌ์‚ฌ์šฉํ•˜์„ธ์š”.\n\n### ์บ์‹œ์™€ ํ\n\n์บ์‹œ, ๋ฉ”์‹œ์ง€ ๋ธŒ๋กœ์ปค, RPC ํด๋ผ์ด์–ธํŠธ๋Š” ์—ฐ๊ฒฐ ํš๋“, ์‘๋‹ต ๋Œ€๊ธฐ, ๊ฐ€๋“ ์ฐฌ ํ์—์„œ ๋ธ”๋กœํ‚น, ๋ฝ ๋Œ€๊ธฐ ๊ฐ™์€ ์ž์ฒด ๋Œ€๊ธฐ ์ง€์ ์„ ๊ฐ€์ง‘๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ์ž‘์—…์ด ctx๋ฅผ ๋ฐ›๋Š”์ง€ ํ™•์ธํ•˜๊ณ  ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์ˆ˜์ค€ ํƒ€์ž„์•„์›ƒ์ด ์žˆ๋‹ค๋ฉด ํ•จ๊ป˜ ์‚ฌ์šฉํ•˜์„ธ์š”.\n\n์‹ค์šฉ์ ์ธ ๊ทœ์น™: ์‚ฌ์šฉ์ž์˜ ์š”์ฒญ์— 800ms๋งŒ ๋‚จ์•˜๋‹ค๋ฉด 2์ดˆ ๊ฑธ๋ฆด ์ˆ˜ ์žˆ๋Š” ํ•˜์œ„ ํ˜ธ์ถœ์„ ์‹œ์ž‘ํ•˜์ง€ ๋งˆ์„ธ์š”. ๊ฑด๋„ˆ๋›ฐ๊ฑฐ๋‚˜ ์—ดํ™”(degrade)ํ•˜๊ฑฐ๋‚˜ ์„ ํƒ์  ํ•„๋“œ์— ๋Œ€ํ•ด ๋ถ€๋ถ„ ์‘๋‹ต์„ ๋ฐ˜ํ™˜ํ•˜์„ธ์š”.\n\nํƒ€์ž„์•„์›ƒ์ด API์—์„œ ๋ฌด์—‡์„ ์˜๋ฏธํ•˜๋Š”์ง€ ๋ฏธ๋ฆฌ ๊ฒฐ์ •ํ•˜์„ธ์š”. ๋•Œ๋กœ๋Š” ๋น ๋ฅธ ์˜ค๋ฅ˜๊ฐ€ ์˜ณ๊ณ , ๋•Œ๋กœ๋Š” ์„ ํƒ์  ํ•„๋“œ์— ๋Œ€ํ•ด ๋ถ€๋ถ„ ๋ฐ์ดํ„ฐ๋ฅผ ์ œ๊ณตํ•˜๊ฑฐ๋‚˜ ์บ์‹œ์˜ ์˜ค๋ž˜๋œ ๋ฐ์ดํ„ฐ๋ฅผ ๋ช…ํ™•ํžˆ ํ‘œ์‹œํ•˜๋Š” ๊ฒƒ์ด ์˜ณ์Šต๋‹ˆ๋‹ค.\n\nAppMaster ๊ฐ™์€ ๋„๊ตฌ๋กœ Go ๋ฐฑ์—”๋“œ๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๊ฒฝ์šฐ(์ƒ์„ฑ๋œ ์ฝ”๋“œ ํฌํ•จ) ์ด ์ฐจ์ด๋Š” "ํƒ€์ž„์•„์›ƒ์ด ์žˆ๋‹ค"์™€ "ํƒ€์ž„์•„์›ƒ์ด ํŠธ๋ž˜ํ”ฝ ๊ธ‰์ฆ ์‹œ์—๋„ ์‹œ์Šคํ…œ์„ ์ผ๊ด€๋˜๊ฒŒ ๋ณดํ˜ธํ•œ๋‹ค"์˜ ์ฐจ์ด์ž…๋‹ˆ๋‹ค.\n\n## ๋‹จ๊ณ„๋ณ„: ์—”๋“œํˆฌ์—”๋“œ ํƒ€์ž„์•„์›ƒ์œผ๋กœ API ๋ฆฌํŒฉํ„ฐ๋งํ•˜๊ธฐ\n\nํƒ€์ž„์•„์›ƒ์„ ์œ„ํ•œ ๋ฆฌํŒฉํ„ฐ๋ง์€ ํ•œ ๊ฐ€์ง€ ์Šต๊ด€์œผ๋กœ ๊ท€๊ฒฐ๋ฉ๋‹ˆ๋‹ค: HTTP ์—์ง€์—์„œ ๋™์ผํ•œ context.Context๋ฅผ ๋ฐ›์•„ ๋ธ”๋กœํ‚นํ•  ์ˆ˜ ์žˆ๋Š” ๋ชจ๋“  ํ˜ธ์ถœ๊นŒ์ง€ ์ „๋‹ฌํ•˜์„ธ์š”.\n\n์‹ค์šฉ์ ์ธ ์ž‘์—… ์ˆœ์„œ๋Š” ์œ„์—์„œ ์•„๋ž˜๋กœ์ž…๋‹ˆ๋‹ค:\n\n- ํ•ธ๋“ค๋Ÿฌ์™€ ํ•ต์‹ฌ ์„œ๋น„์Šค ๋ฉ”์„œ๋“œ๊ฐ€ ctx context.Context๋ฅผ ๋ฐ›๋„๋ก ๋ณ€๊ฒฝํ•˜์„ธ์š”.\n- ๋ชจ๋“  DB ํ˜ธ์ถœ์„ QueryContext๋‚˜ ExecContext๋กœ ์—…๋ฐ์ดํŠธํ•˜์„ธ์š”.\n- ์™ธ๋ถ€ ํ˜ธ์ถœ(HTTP ํด๋ผ์ด์–ธํŠธ, ์บ์‹œ, ํ)๋„ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ์ฒ˜๋ฆฌํ•˜์„ธ์š”. ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ctx๋ฅผ ๋ฐ›์ง€ ์•Š์œผ๋ฉด ๋ž˜ํ•‘ํ•˜๊ฑฐ๋‚˜ ๊ต์ฒดํ•˜์„ธ์š”.\n- ํƒ€์ž„์•„์›ƒ์˜ ์†Œ์œ ์ž๋ฅผ ๊ฒฐ์ •ํ•˜์„ธ์š”. ์ผ๋ฐ˜ ๊ทœ์น™: ํ•ธ๋“ค๋Ÿฌ๊ฐ€ ์ „์ฒด ๋ฐ๋“œ๋ผ์ธ์„ ์„ค์ •ํ•˜๊ณ , ํ•˜์œ„ ๋ ˆ์ด์–ด๋Š” ํ•„์š”ํ•  ๋•Œ๋งŒ ๋” ์งง์€ ๋ฐ๋“œ๋ผ์ธ์„ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.\n- ์—์ง€์—์„œ๋Š” context.DeadlineExceeded์™€ context.Canceled๋ฅผ ๋ช…ํ™•ํ•œ HTTP ์‘๋‹ต์œผ๋กœ ๋งคํ•‘ํ•ด ์˜ค๋ฅ˜๊ฐ€ ์˜ˆ์ธก ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•˜์„ธ์š”.\n\n๋ ˆ์ด์–ด ์ „๋ฐ˜์— ๊ฑธ์นœ ํ˜•ํƒœ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:\n\ngo\nfunc (h *Handler) GetOrder(w http.ResponseWriter, r *http.Request) {\n ctx, cancel := context.WithTimeout(r.Context(), 2*time.Second)\n defer cancel()\n\n order, err := h.svc.GetOrder(ctx, r.PathValue(\"id\"))\n if errors.Is(err, context.DeadlineExceeded) {\n http.Error(w, \"request timed out\", http.StatusGatewayTimeout)\n return\n }\n if err != nil {\n http.Error(w, \"internal error\", http.StatusInternalServerError)\n return\n }\n _ = json.NewEncoder(w).Encode(order)\n}\n\nfunc (r *Repo) GetOrder(ctx context.Context, id string) (Order, error) {\n row := r.db.QueryRowContext(ctx, `SELECT id,total FROM orders WHERE id=$1`, id)\n // scan...\n}\n\n\nํƒ€์ž„์•„์›ƒ ๊ฐ’์€ ์ง€๋ฃจํ•˜๊ฒŒ(์ผ๊ด€๋˜๊ฒŒ) ์„ค์ •ํ•˜์„ธ์š”. ํ•ธ๋“ค๋Ÿฌ์— ์ด 2์ดˆ๊ฐ€ ์žˆ๋‹ค๋ฉด DB ์ฟผ๋ฆฌ๋Š” JSON ์ธ์ฝ”๋”ฉ๊ณผ ๊ธฐํƒ€ ์ž‘์—…์„ ์œ„ํ•œ ์—ฌ์œ ๋ฅผ ๋‚จ๊ฒจ 1์ดˆ ์ดํ•˜๋กœ ์œ ์ง€ํ•˜์„ธ์š”.\n\n์ž‘๋™์„ ์ฆ๋ช…ํ•˜๋ ค๋ฉด ํƒ€์ž„์•„์›ƒ์„ ๊ฐ•์ œํ•˜๋Š” ํ…Œ์ŠคํŠธ๋ฅผ ์ถ”๊ฐ€ํ•˜์„ธ์š”. ๊ฐ„๋‹จํ•œ ๋ฐฉ๋ฒ•์€ ctx.Done()๊นŒ์ง€ ๋ธ”๋กํ•œ ๋’ค ctx.Err()๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ํŽ˜์ดํฌ ๋ ˆํฌ๋ฅผ ๋งŒ๋“œ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ํ…Œ์ŠคํŠธ๋Š” ํ•ธ๋“ค๋Ÿฌ๊ฐ€ ํŽ˜์ดํฌ ์ง€์—ฐ ์ดํ›„๊ฐ€ ์•„๋‹ˆ๋ผ ๋น ๋ฅด๊ฒŒ 504์„ ๋ฐ˜ํ™˜ํ•˜๋Š”์ง€ ํ™•์ธํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.\n\nAppMaster๋กœ Go ๋ฐฑ์—”๋“œ๋ฅผ ์ƒ์„ฑํ•œ๋‹ค๋ฉด ๊ทœ์น™์€ ๋™์ผํ•ฉ๋‹ˆ๋‹ค: ํ•˜๋‚˜์˜ ์š”์ฒญ ์ปจํ…์ŠคํŠธ๋ฅผ ๋ชจ๋“  ๊ณณ์— ์“ฐ๊ณ  ๋ฐ๋“œ๋ผ์ธ ์†Œ์œ ๊ถŒ์„ ๋ช…ํ™•ํžˆ ํ•˜์„ธ์š”.\n\n## ๊ด€์ฐฐ์„ฑ: ํƒ€์ž„์•„์›ƒ์ด ์ž‘๋™ํ•˜๋Š”์ง€ ์ฆ๋ช…ํ•˜๊ธฐ\n\nํƒ€์ž„์•„์›ƒ์€ ์‹ค์ œ๋กœ ์ผ์–ด๋‚˜๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ์–ด์•ผ๋งŒ ๋„์›€์ด ๋ฉ๋‹ˆ๋‹ค. ๋ชฉํ‘œ๋Š” ๊ฐ„๋‹จํ•ฉ๋‹ˆ๋‹ค: ๋ชจ๋“  ์š”์ฒญ์— ๋ฐ๋“œ๋ผ์ธ์ด ์žˆ๊ณ  ์‹คํŒจํ–ˆ์„ ๋•Œ ์‹œ๊ฐ„์ด ์–ด๋””์— ์†Œ๋ชจ๋˜์—ˆ๋Š”์ง€ ์•Œ ์ˆ˜ ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.\n\n๋ฌดํ•ดํ•˜๋ฉด์„œ๋„ ์œ ์šฉํ•œ ๋กœ๊ทธ๋ถ€ํ„ฐ ์‹œ์ž‘ํ•˜์„ธ์š”. ์ „์ฒด ์š”์ฒญ ๋ณธ๋ฌธ์„ ๋คํ”„ํ•˜๋Š” ๋Œ€์‹  ์š”์ฒญ ID(๋˜๋Š” ํŠธ๋ ˆ์ด์Šค ID), ๋ฐ๋“œ๋ผ์ธ์ด ์„ค์ •๋˜์–ด ์žˆ๋Š”์ง€์™€ ์ฃผ์š” ์ง€์ ์—์„œ ๋‚จ์€ ์‹œ๊ฐ„, ์ž‘์—… ์ด๋ฆ„(ํ•ธ๋“ค๋Ÿฌ, SQL ์ฟผ๋ฆฌ ์ด๋ฆ„, ์•„์›ƒ๋ฐ”์šด๋“œ ํ˜ธ์ถœ ์ด๋ฆ„), ๊ฒฐ๊ณผ ๋ถ„๋ฅ˜(ok, timeout, canceled, other error) ์ •๋„๋งŒ ๊ธฐ๋กํ•˜๋ฉด ๋А๋ฆฐ ๊ฒฝ๋กœ๋ฅผ ์ถ”์ ํ•˜๊ธฐ ์ถฉ๋ถ„ํ•ฉ๋‹ˆ๋‹ค.\n\nํ–‰๋™์„ ๋ช…ํ™•ํžˆ ๋ณด์—ฌ์ฃผ๋Š” ๋ช‡ ๊ฐ€์ง€ ์ง‘์ค‘๋œ ๋ฉ”ํŠธ๋ฆญ์„ ์ถ”๊ฐ€ํ•˜์„ธ์š”:\n\n- ์—”๋“œํฌ์ธํŠธ ๋ฐ ์ข…์†์„ฑ๋ณ„ ํƒ€์ž„์•„์›ƒ ์นด์šดํŠธ\n- ์š”์ฒญ ์ง€์—ฐ(p50/p95/p99)\n- ์ธํ”Œ๋ผ์ดํŠธ ์š”์ฒญ ์ˆ˜\n- ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ฟผ๋ฆฌ ์ง€์—ฐ(p95/p99)\n- ์˜ค๋ฅ˜์œจ(์œ ํ˜•๋ณ„ ๋ถ„๋ฆฌ)\n\n์˜ค๋ฅ˜๋ฅผ ์ฒ˜๋ฆฌํ•  ๋•Œ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ํƒœ๊น…ํ•˜์„ธ์š”. context.DeadlineExceeded๋Š” ๋ณดํ†ต ์˜ˆ์‚ฐ์„ ์ดˆ๊ณผํ–ˆ๋‹ค๋Š” ์˜๋ฏธ์ด๊ณ , context.Canceled๋Š” ํด๋ผ์ด์–ธํŠธ๊ฐ€ ๋– ๋‚ฌ๊ฑฐ๋‚˜ ์ƒ์œ„ ํƒ€์ž„์•„์›ƒ์ด ๋จผ์ € ๋ฐœ์ƒํ–ˆ๋‹ค๋Š” ๋œป์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‘˜์€ ์›์ธ๊ณผ ํ•ด๊ฒฐ์ฑ…์ด ๋‹ค๋ฅด๋ฏ€๋กœ ๋ถ„๋ฆฌํ•ด์„œ ๊ธฐ๋กํ•˜์„ธ์š”.\n\n### ํŠธ๋ ˆ์ด์‹ฑ: ์‹œ๊ฐ„์ด ์–ด๋””๋กœ ๊ฐ€๋Š”์ง€ ์ฐพ๊ธฐ\n\nํŠธ๋ ˆ์ด์Šค ์ŠคํŒฌ์€ HTTP ํ•ธ๋“ค๋Ÿฌ์—์„œ database/sql์˜ QueryContext ํ˜ธ์ถœ๊นŒ์ง€ ๋™์ผํ•œ ์ปจํ…์ŠคํŠธ๋ฅผ ๋”ฐ๋ผ์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ์š”์ฒญ์ด 2์ดˆ์—์„œ ํƒ€์ž„์•„์›ƒ ๋˜๊ณ  ํŠธ๋ ˆ์ด์Šค ์ƒ์— DB ์—ฐ๊ฒฐ ๋Œ€๊ธฐ์—์„œ 1.8์ดˆ๊ฐ€ ์†Œ์š”๋œ ๊ฒƒ์ด ๋ณด์ด๋ฉด ์ด๋Š” ์ฟผ๋ฆฌ ํ…์ŠคํŠธ ๋ฌธ์ œ๊ฐ€ ์•„๋‹ˆ๋ผ ํ’€ ํฌ๊ธฐ๋‚˜ ๋А๋ฆฐ ํŠธ๋žœ์žญ์…˜ ๋ฌธ์ œ๋ฅผ ๊ฐ€๋ฆฌํ‚ต๋‹ˆ๋‹ค.\n\nํƒ€์ž„์•„์›ƒ๋ณ„ ๋Œ€์‹œ๋ณด๋“œ(์—”๋“œํฌ์ธํŠธ๋ณ„ ํƒ€์ž„์•„์›ƒ, ์ƒ์œ„ ๋А๋ฆฐ ์ฟผ๋ฆฌ ๋“ฑ)๋ฅผ ๋‚ด๋ถ€์ ์œผ๋กœ ๊ตฌ์ถ•ํ•˜๋ฉด ํšŒ๊ท€๋ฅผ ๋นจ๋ฆฌ ๋ฐœ๊ฒฌํ•˜๋Š” ๋ฐ ๋„์›€์ด ๋ฉ๋‹ˆ๋‹ค. AppMaster ๊ฐ™์€ ๋…ธ์ฝ”๋“œ ๋„๊ตฌ๋Š” ๊ด€์ฐฐ์„ฑ ๊ธฐ๋Šฅ์„ ๋ณ„๋„ ์—”์ง€๋‹ˆ์–ด๋ง ํ”„๋กœ์ ํŠธ๋กœ ์ง„ํ–‰ํ•˜์ง€ ์•Š๊ณ ๋„ ๋น ๋ฅด๊ฒŒ ๋ฐฐํฌํ•  ๋•Œ ์œ ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.\n\n## ํƒ€์ž„์•„์›ƒ์„ ๋ฌด๋ ฅํ™”ํ•˜๋Š” ํ”ํ•œ ์‹ค์ˆ˜๋“ค\n\n๋Œ€๋ถ€๋ถ„์˜ "๊ฐ€๋” ์—ฌ์ „ํžˆ ๋ฉˆ์ถ˜๋‹ค" ๋ฒ„๊ทธ๋Š” ๋ช‡ ๊ฐ€์ง€ ์ž‘์€ ์‹ค์ˆ˜์—์„œ ์˜ต๋‹ˆ๋‹ค.\n\n- ์ค‘๊ฐ„์— ์‹œ๊ณ„๋ฅผ ์žฌ์„ค์ •ํ•˜๋Š” ๊ฒƒ. ํ•ธ๋“ค๋Ÿฌ๊ฐ€ 2์ดˆ ๋ฐ๋“œ๋ผ์ธ์„ ์„ค์ •ํ–ˆ๋Š”๋ฐ ๋ ˆํฌ์ง€ํ† ๋ฆฌ๊ฐ€ ์ž์ฒด ํƒ€์ž„์•„์›ƒ์„ ์ƒˆ๋กœ ๋งŒ๋“ค๊ฑฐ๋‚˜(๋˜๋Š” ์•„์˜ˆ ํƒ€์ž„์•„์›ƒ ์—†์ด) ํ•˜๋ฉด ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๊ฐ€ ํด๋ผ์ด์–ธํŠธ๊ฐ€ ๋– ๋‚œ ๋’ค์—๋„ ์‹คํ–‰๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋“ค์–ด์˜จ ctx๋ฅผ ๊ทธ๋Œ€๋กœ ์ „๋‹ฌํ•˜๊ณ , ๋ถ„๋ช…ํ•œ ์ด์œ ๊ฐ€ ์žˆ์„ ๋•Œ๋งŒ ๋” ์งง๊ฒŒ ์กฐ์ด๋Š” ์ž์‹ ์ปจํ…์ŠคํŠธ๋ฅผ ๋งŒ๋“œ์„ธ์š”.\n- ๋ฉˆ์ถ”์ง€ ์•Š๋Š” ๊ณ ๋ฃจํ‹ด ์‹œ์ž‘. context.Background()๋กœ ์ž‘์—…์„ ์‹œ์ž‘ํ•˜๊ฑฐ๋‚˜ ctx๋ฅผ ๋ฒ„๋ฆฌ๋ฉด ์š”์ฒญ์ด ์ทจ์†Œ๋œ ๋’ค์—๋„ ์ž‘์—…์ด ๊ณ„์† ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค. ๊ณ ๋ฃจํ‹ด์— ์š”์ฒญ ctx๋ฅผ ์ „๋‹ฌํ•˜๊ณ  select๋กœ ctx.Done()์„ ๊ฐ์‹œํ•˜์„ธ์š”.\n- ์‹ค์ œ ํŠธ๋ž˜ํ”ฝ์— ๋น„ํ•ด ๋„ˆ๋ฌด ์งง์€ ๋ฐ๋“œ๋ผ์ธ. 50ms ํƒ€์ž„์•„์›ƒ์€ ๋กœ์ปฌ์—์„œ๋Š” ๊ดœ์ฐฎ์•„ ๋ณด์—ฌ๋„ ํ”„๋กœ๋•์…˜์˜ ์ž‘์€ ์ŠคํŒŒ์ดํฌ์—์„œ๋Š” ์‹คํŒจ๋ฅผ ์ดˆ๋ž˜ํ•ด ์žฌ์‹œ๋„์™€ ์ถ”๊ฐ€ ๋ถ€ํ•˜๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ •์ƒ ์ง€์—ฐ๊ณผ ์—ฌ์œ ๋ฅผ ๊ณ ๋ คํ•ด ํƒ€์ž„์•„์›ƒ์„ ์ •ํ•˜์„ธ์š”.\n- ์‹ค์ œ ์˜ค๋ฅ˜๋ฅผ ์ˆจ๊ธฐ๋Š” ๊ฒƒ. context.DeadlineExceeded๋ฅผ ์ผ๋ฐ˜ 500์œผ๋กœ ์ฒ˜๋ฆฌํ•˜๋ฉด ๋””๋ฒ„๊น…๊ณผ ํด๋ผ์ด์–ธํŠธ ๋™์ž‘์ด ์•…ํ™”๋ฉ๋‹ˆ๋‹ค. ํƒ€์ž„์•„์›ƒ ์‘๋‹ต์„ ๋ช…ํ™•ํžˆ ํ•˜๊ณ  "ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์ทจ์†Œํ•จ"๊ณผ "์˜ˆ์‚ฐ ์ดˆ๊ณผ๋กœ ํƒ€์ž„์•„์›ƒ๋จ"์˜ ์ฐจ์ด๋ฅผ ๋กœ๊ทธ์— ๋‚จ๊ธฐ์„ธ์š”.\n- ์กฐ๊ธฐ ์ข…๋ฃŒ ์‹œ ์ž์› ๋‹ซ๊ธฐ ๋ˆ„๋ฝ. ์กฐ๊ธฐ ๋ฐ˜ํ™˜ ์‹œ์—๋„ defer rows.Close()์™€ context.WithTimeout์˜ cancel ํ˜ธ์ถœ์„ ํ™•์‹คํžˆ ํ•˜์„ธ์š”. ์œ ์ถœ๋œ rows๋‚˜ ๋‚จ์€ ์ž‘์—…์€ ๋ถ€ํ•˜ ์‹œ ์—ฐ๊ฒฐ์„ ๊ณ ๊ฐˆ์‹œํ‚ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.\n\n๊ฐ„๋‹จํ•œ ์˜ˆ: ์—”๋“œํฌ์ธํŠธ๊ฐ€ ๋ฆฌํฌํŠธ ์ฟผ๋ฆฌ๋ฅผ ํŠธ๋ฆฌ๊ฑฐํ•ฉ๋‹ˆ๋‹ค. ์‚ฌ์šฉ์ž๊ฐ€ ํƒญ์„ ๋‹ซ์œผ๋ฉด ํ•ธ๋“ค๋Ÿฌ ctx๋Š” ์ทจ์†Œ๋ฉ๋‹ˆ๋‹ค. ๋งŒ์•ฝ SQL ํ˜ธ์ถœ์ด background ์ปจํ…์ŠคํŠธ๋ฅผ ์‚ฌ์šฉํ–ˆ๋‹ค๋ฉด ์ฟผ๋ฆฌ๋Š” ๊ณ„์† ์‹คํ–‰๋˜์–ด ์—ฐ๊ฒฐ์„ ์žก์•„๋‘๊ณ  ๋ชจ๋‘๋ฅผ ๋А๋ฆฌ๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค. ๋™์ผํ•œ ctx๋ฅผ QueryContext์— ์ „๋‹ฌํ•˜๋ฉด ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ํ˜ธ์ถœ์ด ์ค‘๋‹จ๋˜์–ด ์‹œ์Šคํ…œ์ด ๋” ๋นจ๋ฆฌ ํšŒ๋ณตํ•ฉ๋‹ˆ๋‹ค.\n\n## ์•ˆ์ •์ ์ธ ํƒ€์ž„์•„์›ƒ ๋™์ž‘์„ ์œ„ํ•œ ๋น ๋ฅธ ์ฒดํฌ๋ฆฌ์ŠคํŠธ\n\nํƒ€์ž„์•„์›ƒ์€ ์ผ๊ด€๋˜์–ด์•ผ๋งŒ ๋„์›€์ด ๋ฉ๋‹ˆ๋‹ค. ํ•˜๋‚˜์˜ ๋ˆ„๋ฝ๋œ ํ˜ธ์ถœ์ด ๊ณ ๋ฃจํ‹ด์„ ๋ฐ”์˜๊ฒŒ ํ•˜๊ณ  DB ์—ฐ๊ฒฐ์„ ์žก์•„๋‘๋ฉฐ ๋‹ค์Œ ์š”์ฒญ๋“ค์„ ๋А๋ฆฌ๊ฒŒ ๋งŒ๋“ญ๋‹ˆ๋‹ค.\n\n- ์—์ง€(๋Œ€๊ฐœ HTTP ํ•ธ๋“ค๋Ÿฌ)์—์„œ ํ•˜๋‚˜์˜ ๋ช…ํ™•ํ•œ ๋ฐ๋“œ๋ผ์ธ์„ ์„ค์ •ํ•˜์„ธ์š”. ์š”์ฒญ ๋‚ด๋ถ€์˜ ๋ชจ๋“  ๊ฒƒ์€ ์ด๋ฅผ ์ƒ์†ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.\n- ์„œ๋น„์Šค์™€ ๋ ˆํฌ์ง€ํ† ๋ฆฌ ๋ ˆ์ด์–ด์— ๋™์ผํ•œ ctx๋ฅผ ์ „๋‹ฌํ•˜์„ธ์š”. ์š”์ฒญ ์ฝ”๋“œ์—์„œ context.Background()๋ฅผ ํ”ผํ•˜์„ธ์š”.\n- DB์—์„œ๋Š” ํ•ญ์ƒ ์ปจํ…์ŠคํŠธ ์ธ์‹ ๋ฉ”์„œ๋“œ(QueryContext, QueryRowContext, ExecContext)๋ฅผ ์‚ฌ์šฉํ•˜์„ธ์š”.\n- ์•„์›ƒ๋ฐ”์šด๋“œ ํ˜ธ์ถœ(HTTP, ์บ์‹œ, ํ)์—๋„ ๋™์ผํ•œ ctx๋ฅผ ๋ถ™์ด์„ธ์š”. ์ž์‹ ์ปจํ…์ŠคํŠธ๋ฅผ ๋งŒ๋“ ๋‹ค๋ฉด ๋” ๊ธธ๊ฒŒ ํ•˜์ง€ ๋ง๊ณ  ๋” ์งง๊ฒŒ ๋งŒ๋“œ์„ธ์š”.\n- ์ทจ์†Œ์™€ ํƒ€์ž„์•„์›ƒ์„ ์ผ๊ด€๋˜๊ฒŒ ์ฒ˜๋ฆฌํ•˜์„ธ์š”: ๋ช…ํ™•ํ•œ ์˜ค๋ฅ˜๋ฅผ ๋ฐ˜ํ™˜ํ•˜๊ณ  ์ž‘์—…์„ ๋ฉˆ์ถ”๋ฉฐ ์ทจ์†Œ๋œ ์š”์ฒญ ๋‚ด์—์„œ ์žฌ์‹œ๋„ ๋ฃจํ”„๋ฅผ ๋งŒ๋“ค์ง€ ๋งˆ์„ธ์š”.\n\n๊ทธ๋‹ค์Œ ๋ถ€ํ•˜ ํ…Œ์ŠคํŠธ๋กœ ๋™์ž‘์„ ๊ฒ€์ฆํ•˜์„ธ์š”. ํƒ€์ž„์•„์›ƒ์ด ํŠธ๋ฆฌ๊ฑฐ๋˜์ง€๋งŒ ์ž์›์„ ์ถฉ๋ถ„ํžˆ ๋นจ๋ฆฌ ํ•ด์ œํ•˜์ง€ ๋ชปํ•˜๋ฉด ์—ฌ์ „ํžˆ ์‹ ๋ขฐ์„ฑ์ด ๋–จ์–ด์ง‘๋‹ˆ๋‹ค.\n\n๋Œ€์‹œ๋ณด๋“œ๋Š” ํƒ€์ž„์•„์›ƒ์„ ํ‰๊ท ๊ฐ’ ์•ˆ์— ์ˆจ๊ธฐ์ง€ ๋ง๊ณ  ๋ช…ํ™•ํžˆ ๋ณด์—ฌ์ค˜์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋ช‡ ๊ฐ€์ง€ ์‹ ํ˜ธ๋ฅผ ์ถ”์ ํ•˜๋ฉด "๋ฐ๋“œ๋ผ์ธ์ด ์‹ค์ œ๋กœ ๊ฐ•์ œ๋˜๊ณ  ์žˆ๋Š”๊ฐ€?"๋ผ๋Š” ์งˆ๋ฌธ์— ๋‹ตํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค: ์š”์ฒญ ํƒ€์ž„์•„์›ƒ๊ณผ DB ํƒ€์ž„์•„์›ƒ(๋ณ„๊ฐœ), ์ง€์—ฐ ๋ฐฑ๋ถ„์œ„์ˆ˜(p95/p99), DB ํ’€ ํ†ต๊ณ„(์‚ฌ์šฉ ์ค‘ ์—ฐ๊ฒฐ ์ˆ˜, ๋Œ€๊ธฐ ํšŸ์ˆ˜, ๋Œ€๊ธฐ ์‹œ๊ฐ„), ๊ทธ๋ฆฌ๊ณ  ์˜ค๋ฅ˜ ์›์ธ ๋ถ„ํ•ด(context deadline exceeded ๋Œ€ ๊ธฐํƒ€ ์‹คํŒจ).\n\nAppMaster ๊ฐ™์€ ํ”Œ๋žซํผ์œผ๋กœ ๋‚ด๋ถ€ ๋„๊ตฌ๋ฅผ ๋งŒ๋“ ๋‹ค๋ฉด ๋™์ผํ•œ ์ฒดํฌ๋ฆฌ์ŠคํŠธ๋Š” ๋ชจ๋“  Go ์„œ๋น„์Šค์— ์ ์šฉ๋ฉ๋‹ˆ๋‹ค: ๊ฒฝ๊ณ„์—์„œ ๋ฐ๋“œ๋ผ์ธ์„ ์ •์˜ํ•˜๊ณ , ์ „๋‹ฌํ•˜๊ณ , ๋ฉ”ํŠธ๋ฆญ์œผ๋กœ ํ™•์ธํ•˜์„ธ์š”.\n\n## ์˜ˆ์‹œ ์‹œ๋‚˜๋ฆฌ์˜ค์™€ ๋‹ค์Œ ๋‹จ๊ณ„\n\n์ด๊ฒŒ ํšจ๊ณผ๋ฅผ ๋ณด๋Š” ์ผ๋ฐ˜์ ์ธ ๊ณณ์€ ๊ฒ€์ƒ‰ ์—”๋“œํฌ์ธํŠธ์ž…๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด GET /search?q=printer๊ฐ€ ํฐ ๋ฆฌํฌํŠธ ์ฟผ๋ฆฌ๋กœ DB๊ฐ€ ๋ฐ”์  ๋•Œ ๋А๋ ค์ง„๋‹ค๊ณ  ๊ฐ€์ •ํ•ด๋ณด์„ธ์š”. ๋ฐ๋“œ๋ผ์ธ์ด ์—†๋‹ค๋ฉด ๋“ค์–ด์˜ค๋Š” ๊ฐ ์š”์ฒญ์ด ๊ธด SQL ์ฟผ๋ฆฌ๋ฅผ ๊ธฐ๋‹ค๋ฆฌ๋ฉฐ ๋Œ€๊ธฐํ•ฉ๋‹ˆ๋‹ค. ๋ถ€ํ•˜๊ฐ€ ๊ฑธ๋ฆฌ๋ฉด ์ด๋Ÿฐ ๋ฉˆ์ถ˜ ์š”์ฒญ๋“ค์ด ์Œ“์—ฌ ๊ณ ๋ฃจํ‹ด๊ณผ ์—ฐ๊ฒฐ์„ ๋ฌถ์–ด๋‘์–ด API ์ „์ฒด๊ฐ€ ์ •์ง€ํ•œ ๊ฒƒ์ฒ˜๋Ÿผ ๋А๊ปด์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.\n\nHTTP ํ•ธ๋“ค๋Ÿฌ์—์„œ ๋ช…ํ™•ํ•œ ๋ฐ๋“œ๋ผ์ธ์„ ์„ค์ •ํ•˜๊ณ  ๋™์ผํ•œ ctx๋ฅผ ๋ ˆํฌ์ง€ํ† ๋ฆฌ๊นŒ์ง€ ์ „๋‹ฌํ•˜๋ฉด ์˜ˆ์‚ฐ์ด ์†Œ์ง„๋  ๋•Œ ์‹œ์Šคํ…œ์€ ๊ธฐ๋‹ค๋ฆผ์„ ๋ฉˆ์ถฅ๋‹ˆ๋‹ค. ๋ฐ๋“œ๋ผ์ธ์ด ๋„๋‹ฌํ•˜๋ฉด DB ๋“œ๋ผ์ด๋ฒ„๊ฐ€(์ง€์›๋˜๋Š” ๊ฒฝ์šฐ) ์ฟผ๋ฆฌ๋ฅผ ์ทจ์†Œํ•˜๊ณ  ํ•ธ๋“ค๋Ÿฌ๋Š” ๋ฐ˜ํ™˜ํ•˜๋ฉฐ, ์„œ๋ฒ„๋Š” ์˜ค๋ž˜๋œ ์š”์ฒญ๋“ค ๋•Œ๋ฌธ์— ์ƒˆ๋กœ์šด ์š”์ฒญ์„ ์„œ๋น™ํ•˜์ง€ ๋ชปํ•˜๋Š” ๋Œ€์‹  ๊ณ„์† ์ƒˆ ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.\n\n๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•ด๋„ ์‚ฌ์šฉ์ž์—๊ฒŒ ๋ณด์ด๋Š” ๋™์ž‘์ด ๋” ๋‚˜์•„์ง‘๋‹ˆ๋‹ค. 30~120์ดˆ ๋™์•ˆ ๋ฉˆ์ถฐ์žˆ๋‹ค๊ฐ€ ์—‰์„ฑํ•˜๊ฒŒ ์‹คํŒจํ•˜๋Š” ๋Œ€์‹  ํด๋ผ์ด์–ธํŠธ๋Š” ๋น ๋ฅด๊ณ  ์˜ˆ์ธก ๊ฐ€๋Šฅํ•œ ์˜ค๋ฅ˜(๋ณดํ†ต 504 ๋˜๋Š” ๊ฐ„๋‹จํ•œ ๋ฉ”์‹œ์ง€ "request timed out")๋ฅผ ๋ฐ›์Šต๋‹ˆ๋‹ค. ๋” ์ค‘์š”ํ•˜๊ฒŒ๋Š” ์‹œ์Šคํ…œ์ด ๋นจ๋ฆฌ ํšŒ๋ณตํ•ฉ๋‹ˆ๋‹ค.\n\n์ด ๊ทœ์น™์„ ์—”๋“œํฌ์ธํŠธ์™€ ํŒ€ ์ „๋ฐ˜์— ์ •์ฐฉ์‹œํ‚ค๊ธฐ ์œ„ํ•œ ๋‹ค์Œ ๋‹จ๊ณ„ ์ œ์•ˆ:\n\n- ์—”๋“œํฌ์ธํŠธ ์œ ํ˜•๋ณ„ ํ‘œ์ค€ ํƒ€์ž„์•„์›ƒ(๊ฒ€์ƒ‰ vs ์“ฐ๊ธฐ vs ๋‚ด๋ณด๋‚ด๊ธฐ)์„ ์ •ํ•˜์„ธ์š”.\n- ์ฝ”๋“œ ๋ฆฌ๋ทฐ์—์„œ QueryContext์™€ ExecContext ์‚ฌ์šฉ์„ ์š”๊ตฌํ•˜์„ธ์š”.\n- ๊ฐ€์žฅ์ž๋ฆฌ์—์„œ ํƒ€์ž„์•„์›ƒ ์˜ค๋ฅ˜๋ฅผ ๋ช…ํ™•ํžˆ(์ƒํƒœ ์ฝ”๋“œ, ๊ฐ„๋‹จํ•œ ๋ฉ”์‹œ์ง€) ์ฒ˜๋ฆฌํ•˜์„ธ์š”.\n- ํƒ€์ž„์•„์›ƒ๊ณผ ์ทจ์†Œ์— ๋Œ€ํ•œ ๋ฉ”ํŠธ๋ฆญ์„ ์ถ”๊ฐ€ํ•ด ํšŒ๊ท€๋ฅผ ์กฐ๊ธฐ์— ๋ฐœ๊ฒฌํ•˜์„ธ์š”.\n- ๋ชจ๋“  ํ•ธ๋“ค๋Ÿฌ๊ฐ€ ๋™์ผํ•˜๊ฒŒ ๋™์ž‘ํ•˜๋„๋ก ์ปจํ…์ŠคํŠธ ์ƒ์„ฑ๊ณผ ๋กœ๊น…์„ ๊ฐ์‹ธ๋Š” ํ—ฌํผ๋ฅผ ํ•˜๋‚˜ ์ž‘์„ฑํ•˜์„ธ์š”.\n\nAppMaster๋กœ ์„œ๋น„์Šค์™€ ๋‚ด๋ถ€ ๋„๊ตฌ๋ฅผ ๊ตฌ์ถ•ํ•œ๋‹ค๋ฉด ์ด๋Ÿฌํ•œ ํƒ€์ž„์•„์›ƒ ๊ทœ์น™์„ ์ƒ์„ฑ๋œ Go ๋ฐฑ์—”๋“œ, API ํ†ตํ•ฉ, ๋Œ€์‹œ๋ณด๋“œ ์ „๋ฐ˜์— ์ผ๊ด€๋˜๊ฒŒ ์ ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. AppMaster๋Š” appmaster.io์— ์ œ๊ณต๋˜๋ฉฐ(๋…ธ์ฝ”๋“œ, ์‹ค์ œ Go ์†Œ์Šค ์ฝ”๋“œ ์ƒ์„ฑ), ์ˆ˜๋™์œผ๋กœ ๋ชจ๋“  ๊ด€๋ฆฌ์ž ๋„๊ตฌ๋ฅผ ์ง์ ‘ ๋งŒ๋“ค์ง€ ์•Š๊ณ ๋„ ์ผ๊ด€๋œ ์š”์ฒญ ์ฒ˜๋ฆฌ์™€ ๊ด€์ฐฐ์„ฑ์„ ํ™•๋ณดํ•  ๋•Œ ์‹ค์šฉ์ ์ธ ์„ ํƒ์ด ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ž์ฃผ ๋ฌป๋Š” ์งˆ๋ฌธ

Go API์—์„œ ์š”์ฒญ์ด โ€œ๋ฉˆ์ท„๋‹คโ€๋Š” ๊ฑด ๋ฌด์Šจ ๋œป์ธ๊ฐ€์š”?

์š”์ฒญ์ด โ€œ๋ฉˆ์ถฐ๋ฒ„๋ ธ๋‹ค(stuck)โ€๋Š” ๊ฒƒ์€ ๋А๋ฆฐ SQL ์ฟผ๋ฆฌ, ํ’€์—์„œ ๋ง‰ํžŒ ์—ฐ๊ฒฐ, DNS ๋ฌธ์ œ, ๋˜๋Š” ์‘๋‹ตํ•˜์ง€ ์•Š๋Š” ์ƒ์œ„ ์„œ๋น„์Šค์ฒ˜๋Ÿผ ๋ฐ˜ํ™˜ํ•˜์ง€ ์•Š๋Š” ๋ฌด์–ธ๊ฐ€๋ฅผ ๊ธฐ๋‹ค๋ฆฌ๊ณ  ์žˆ์„ ๋•Œ๋ฅผ ๋งํ•ฉ๋‹ˆ๋‹ค. ๋ถ€ํ•˜๊ฐ€ ๊ฑธ๋ฆฌ๋ฉด ์ด๋Ÿฐ ๋ฉˆ์ถ˜ ์š”์ฒญ๋“ค์ด ์Œ“์—ฌ ์ž‘์—…์ž์™€ ์—ฐ๊ฒฐ์„ ๋ฌถ์–ด๋‘๊ณ  ์ž‘์€ ์ง€์—ฐ์ด ์ „์ฒด ์žฅ์• ๋กœ ๋ฒˆ์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ํƒ€์ž„์•„์›ƒ์€ ๋ฏธ๋“ค์›จ์–ด, ํ•ธ๋“ค๋Ÿฌ, ์•„๋‹ˆ๋ฉด ์ฝ”๋“œ ๊นŠ์€ ๊ณณ ์–ด๋””์— ์„ค์ •ํ•ด์•ผ ํ•˜๋‚˜์š”?

์ „์ฒด ๋ฐ๋“œ๋ผ์ธ์€ HTTP ๊ฒฝ๊ณ„์—์„œ ์„ค์ •ํ•˜๊ณ  ๊ทธ ๊ฐ™์€ ctx๋ฅผ ๋ธ”๋กœํ‚นํ•  ์ˆ˜ ์žˆ๋Š” ๋ชจ๋“  ๋ ˆ์ด์–ด๋กœ ์ „๋‹ฌํ•˜์„ธ์š”. ์ด ๊ณต์œ ๋œ ๋ฐ๋“œ๋ผ์ธ์ด ๋ช‡ ๋ฒˆ์˜ ๋А๋ฆฐ ์ž‘์—…์ด ์ž์›์„ ์˜ค๋ž˜ ์ ์œ ํ•ด ์ „๋ฐ˜์ ์ธ ํƒ€์ž„์•„์›ƒ์œผ๋กœ ์ด์–ด์ง€๋Š” ๊ฒƒ์„ ๋ง‰์Šต๋‹ˆ๋‹ค.

ํƒ€์ž„์•„์›ƒ์ด ์–ด์ฐจํ”ผ ๋ฐœ๋™ํ•˜๋Š”๋ฐ ์™œ `cancel()`์„ ํ˜ธ์ถœํ•ด์•ผ ํ•˜๋‚˜์š”?

ctx, cancel := context.WithTimeout(r.Context(), d)๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ํ•ธ๋“ค๋Ÿฌ(๋˜๋Š” ๋ฏธ๋“ค์›จ์–ด)์—์„œ ํ•ญ์ƒ defer cancel()์„ ํ˜ธ์ถœํ•˜์„ธ์š”. cancel ํ˜ธ์ถœ์€ ํƒ€์ด๋จธ๋ฅผ ํ•ด์ œํ•˜๊ณ  ์š”์ฒญ์ด ์ผ์ฐ ๋๋‚ฌ์„ ๋•Œ ๊ธฐ๋‹ค๋ฆผ์„ ๋นจ๋ฆฌ ๋ฉˆ์ถ”๋„๋ก ๋•์Šต๋‹ˆ๋‹ค.

ํƒ€์ž„์•„์›ƒ์„ ๋ฌด๋ ฅํ™”ํ•˜๋Š” ๊ฐ€์žฅ ํฐ ์‹ค์ˆ˜๋Š” ๋ฌด์—‡์ธ๊ฐ€์š”?

์š”์ฒญ ์ฝ”๋“œ์—์„œ context.Background()๋‚˜ context.TODO()๋กœ ๋Œ€์ฒดํ•˜๋ฉด ์ทจ์†Œ์™€ ๋ฐ๋“œ๋ผ์ธ ์ฒด์ธ์ด ๋Š๊น๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋ฉด SQL์ด๋‚˜ ์™ธ๋ถ€ HTTP ๊ฐ™์€ ํ•˜์œ„ ์ž‘์—…์ด ํด๋ผ์ด์–ธํŠธ๊ฐ€ ๋– ๋‚œ ๋’ค์—๋„ ๊ณ„์† ์‹คํ–‰๋˜์–ด ํƒ€์ž„์•„์›ƒ์„ ๋ฌด์šฉ์ง€๋ฌผ๋กœ ๋งŒ๋“ญ๋‹ˆ๋‹ค.

`context deadline exceeded`์™€ `context canceled`๋ฅผ ์–ด๋–ป๊ฒŒ ๋‹ค๋ค„์•ผ ํ•˜๋‚˜์š”?

context.DeadlineExceeded์™€ context.Canceled๋Š” ์ •์ƒ์ ์ธ ์ œ์–ด ๊ฒฐ๊ณผ๋กœ ์ทจ๊ธ‰ํ•ด ์ƒ์œ„๋กœ ๊ทธ๋Œ€๋กœ ์ „๋‹ฌํ•˜์„ธ์š”. ๊ฐ€์žฅ์ž๋ฆฌ์—์„œ๋Š” ๋ณดํ†ต ํƒ€์ž„์•„์›ƒ์— ๋Œ€ํ•ด 504 ๊ฐ™์€ ๋ช…ํ™•ํ•œ ์‘๋‹ต์œผ๋กœ ๋งคํ•‘ํ•ด ํด๋ผ์ด์–ธํŠธ๊ฐ€ ๋ฌด์ž‘์ • ์žฌ์‹œ๋„ํ•˜์ง€ ์•Š๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.

database/sql์—์„œ ์–ด๋–ค ํ˜ธ์ถœ์— ์ปจํ…์ŠคํŠธ๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•˜๋‚˜์š”?

ํ•ญ์ƒ ์ปจํ…์ŠคํŠธ๋ฅผ ์ง€์›ํ•˜๋Š” ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์„ธ์š”: QueryContext, QueryRowContext, ExecContext, PrepareContext. Query()๋‚˜ Exec()์ฒ˜๋Ÿผ ์ปจํ…์ŠคํŠธ ์—†๋Š” ํ˜ธ์ถœ์„ ์‚ฌ์šฉํ•˜๋ฉด ํ•ธ๋“ค๋Ÿฌ๋Š” ํƒ€์ž„์•„์›ƒ๋  ์ˆ˜ ์žˆ์–ด๋„ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ํ˜ธ์ถœ์€ ๊ณ„์† ๋ธ”๋กœํ‚น๋˜์–ด ์—ฐ๊ฒฐ์„ ์žก์•„๋‘๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

์ปจํ…์ŠคํŠธ ์ทจ์†Œ๊ฐ€ ์‹ค์ œ๋กœ PostgreSQL์—์„œ ์‹คํ–‰ ์ค‘์ธ ์ฟผ๋ฆฌ๋ฅผ ๋ฉˆ์ถ”๋‚˜์š”?

๋งŽ์€ ๋“œ๋ผ์ด๋ฒ„๊ฐ€ ์ปจํ…์ŠคํŠธ ์ทจ์†Œ๋ฅผ honorํ•˜์ง€๋งŒ, ์ง์ ‘ ๋А๋ฆฐ ์ฟผ๋ฆฌ๋ฅผ ์‹คํ–‰ํ•ด ๋ฐ๋“œ๋ผ์ธ์ด ์ดˆ๊ณผ๋˜์—ˆ์„ ๋•Œ ๋น ๋ฅด๊ฒŒ ์ทจ์†Œ๋˜๋Š”์ง€ ํ™•์ธํ•˜์„ธ์š”. ๋˜ํ•œ ์ผ๋ถ€ ์ฝ”๋“œ ๊ฒฝ๋กœ๊ฐ€ ์ปจํ…์ŠคํŠธ ์ „๋‹ฌ์„ ์žŠ๋Š” ๊ฒฝ์šฐ๋ฅผ ๋Œ€๋น„ํ•ด DB ์ชฝ ๋ฌธ์žฅ(statement) ํƒ€์ž„์•„์›ƒ์„ ๋ฐฑ์Šคํ†ฑ์œผ๋กœ ๋‘๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.

์•„์›ƒ๋ฐ”์šด๋“œ HTTP ํ˜ธ์ถœ์— ๊ฐ™์€ ๋ฐ๋“œ๋ผ์ธ์„ ์–ด๋–ป๊ฒŒ ์ ์šฉํ•˜๋‚˜์š”?

์•„์›ƒ๋ฐ”์šด๋“œ ์š”์ฒญ์„ ๋งŒ๋“ค ๋•Œ http.NewRequestWithContext(ctx, ...)๋กœ ์ƒ์„ฑํ•ด ๋™์ผํ•œ ๋ฐ๋“œ๋ผ์ธ๊ณผ ์ทจ์†Œ ์‹ ํ˜ธ๊ฐ€ ์ „๋‹ฌ๋˜๊ฒŒ ํ•˜์„ธ์š”. ๋˜ํ•œ ๋ˆ„๊ตฐ๊ฐ€ ์‹ค์ˆ˜๋กœ background ์ปจํ…์ŠคํŠธ๋ฅผ ์“ฐ๊ฑฐ๋‚˜ DNS/TLS/์œ ํœด ์—ฐ๊ฒฐ์ด ๋ฉˆ์ถœ ๊ฒฝ์šฐ๋ฅผ ๋Œ€๋น„ํ•ด http.Client.Timeout๊ณผ ํŠธ๋žœ์ŠคํฌํŠธ์˜ ๋‹ค์ด์–ผ/ํ•ธ๋“œ์…ฐ์ดํฌ/์‘๋‹ต ํ—ค๋” ํƒ€์ž„์•„์›ƒ์„ ์„ค์ •ํ•ด ๋‘๋Š” ๊ฒƒ์ด ์•ˆ์ „ํ•ฉ๋‹ˆ๋‹ค.

ํ•˜์œ„ ๋ ˆ์ด์–ด(๋ ˆํฌ/์„œ๋น„์Šค)๊ฐ€ ์ž์ฒด ํƒ€์ž„์•„์›ƒ์„ ๋งŒ๋“ค์–ด๋„ ๋˜๋‚˜์š”?

ํ•˜์œ„ ๋ ˆ์ด์–ด์—์„œ ์‹œ๊ฐ„์„ ๋Š˜๋ฆฌ๋Š” ์ƒˆ๋กœ์šด ์ปจํ…์ŠคํŠธ๋ฅผ ์ƒ์„ฑํ•˜์ง€ ๋งˆ์„ธ์š”. ์ž์‹ ์ปจํ…์ŠคํŠธ๋ฅผ ๋งŒ๋“ค์–ด์•ผ ํ•œ๋‹ค๋ฉด ๋ถ€๋ชจ๋ณด๋‹ค ๋” ์งง๊ฒŒ ์„ค์ •ํ•˜์„ธ์š”. ์š”์ฒญ์— ์‹œ๊ฐ„์ด ๊ฑฐ์˜ ๋‚จ์ง€ ์•Š์•˜๋‹ค๋ฉด ์„ ํƒ์  ํ•˜์œ„ ํ˜ธ์ถœ์„ ๊ฑด๋„ˆ๋›ฐ๊ณ , ๋ถ€๋ถ„ ์‘๋‹ต์„ ๋ฐ˜ํ™˜ํ•˜๊ฑฐ๋‚˜ ๋น ๋ฅด๊ฒŒ ์‹คํŒจํ•˜๋Š” ์ชฝ์ด ๋‚ซ์Šต๋‹ˆ๋‹ค.

์—”๋“œํˆฌ์—”๋“œ ํƒ€์ž„์•„์›ƒ์ด ์ž‘๋™ํ•˜๋Š”์ง€ ๋ฌด์—‡์„ ๋ชจ๋‹ˆํ„ฐ๋งํ•ด์•ผ ํ•˜๋‚˜์š”?

์—”๋“œํˆฌ์—”๋“œ ํƒ€์ž„์•„์›ƒ์ด ์ž‘๋™ํ•˜๋Š”์ง€ ํ™•์ธํ•˜๋ ค๋ฉด ์—”๋“œํฌ์ธํŠธ์™€ ์ข…์†์„ฑ๋ณ„๋กœ ํƒ€์ž„์•„์›ƒ๊ณผ ์ทจ์†Œ๋ฅผ ๋ถ„๋ฆฌํ•ด ์ถ”์ ํ•˜๊ณ , ์ง€์—ฐ ๋ฐฑ๋ถ„์œ„์ˆ˜(p95/p99)์™€ ์ธํ”Œ๋ผ์ดํŠธ ์š”์ฒญ ์ˆ˜๋ฅผ ๋ชจ๋‹ˆํ„ฐ๋งํ•˜์„ธ์š”. ํŠธ๋ ˆ์ด์Šค์—์„œ๋Š” ํ•ธ๋“ค๋Ÿฌ์—์„œ QueryContext ๊ฐ™์€ DB ํ˜ธ์ถœ๊นŒ์ง€ ๋™์ผํ•œ ์ปจํ…์ŠคํŠธ๊ฐ€ ์ด์–ด์ง€๋Š”์ง€ ํ™•์ธํ•˜๋ฉด ์‹œ๊ฐ„์ด ์–ด๋””์— ์†Œ๋ชจ๋๋Š”์ง€ ํŒŒ์•…ํ•˜๊ธฐ ์‰ฝ์Šต๋‹ˆ๋‹ค.

์‰ฌ์šด ์‹œ์ž‘
๋ฉ‹์ง„๋งŒ๋“ค๊ธฐ

๋ฌด๋ฃŒ ์š”๊ธˆ์ œ๋กœ AppMaster๋ฅผ ์‚ฌ์šฉํ•ด ๋ณด์„ธ์š”.
์ค€๋น„๊ฐ€ ๋˜๋ฉด ์ ์ ˆํ•œ ๊ตฌ๋…์„ ์„ ํƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์‹œ์ž‘ํ•˜๋‹ค
API์šฉ Go ์ปจํ…์ŠคํŠธ ํƒ€์ž„์•„์›ƒ: HTTP ํ•ธ๋“ค๋Ÿฌ์—์„œ SQL๊นŒ์ง€ | AppMaster