{"componentChunkName":"component---src-templates-blog-post-js","path":"/javascript/async-localstorage로-nodejs-비동기-컨텍스트-추적하기/","result":{"data":{"site":{"siteMetadata":{"title":"Bottlehs Tech Blog","description":"웹·앱·AI 개발자 전병훈(bottlehs)의 기술 블로그. AI·LLM, JavaScript·Vue, Spring Boot, 알고리즘, 블록체인 실무 가이드를 다룹니다","siteUrl":"https://www.bottlehs.dev","author":{"name":"Jeon Byung Hun","summary":"개발을 즐기는 bottlehs - Engineer, MS, AI, FE, BE, OS, IOT, Blockchain, 설계, 테스트"},"social":{"github":"bottlehs","codepen":"bottlehs"}}},"markdownRemark":{"id":"43f1895c-0081-5a30-89de-bf21b6bc8386","excerpt":"Node.js 애플리케이션은 비동기 호출이 얽히면서 요청별 로깅, 트랜잭션 ID…","html":"<p>Node.js 애플리케이션은 비동기 호출이 얽히면서 요청별 로깅, 트랜잭션 ID 전달, 분산 추적이 끊어지기 쉽다. <code class=\"language-text\">AsyncLocalStorage</code>는 비동기 호출 체인 전체에서 상태를 공유할 수 있도록 <code class=\"language-text\">async_hooks</code> 기반 스코프를 제공한다. 이 글에서는 <code class=\"language-text\">AsyncLocalStorage</code>의 동작 원리, 설치·설정 방법, 프레임워크별 통합 패턴, 운영 중 주의사항을 살펴본다.</p>\n<h2 id=\"개념-정리-asynclocalstorage-스코프-모델\" style=\"position:relative;\"><a href=\"#%EA%B0%9C%EB%85%90-%EC%A0%95%EB%A6%AC-asynclocalstorage-%EC%8A%A4%EC%BD%94%ED%94%84-%EB%AA%A8%EB%8D%B8\" aria-label=\"개념 정리 asynclocalstorage 스코프 모델 permalink\" class=\"anchor-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>개념 정리: AsyncLocalStorage 스코프 모델</h2>\n<p><code class=\"language-text\">AsyncLocalStorage</code>는 Node.js가 제공하는 비동기 컨텍스트 저장소이다. 이벤트 루프에서 태스크가 생성될 때 내부적으로 컨텍스트 맵을 복제해 전달하므로, 콜백·Promise·<code class=\"language-text\">async/await</code> 체인 전반에 동일한 값을 참조할 수 있다.</p>\n<ul>\n<li><strong>컨텍스트 격리</strong>: 요청마다 독립적인 스토어 인스턴스를 생성해 데이터 경쟁을 방지한다.  </li>\n<li><strong>비동기 호환성</strong>: <code class=\"language-text\">await</code>, 타이머, I/O, Worker Threads에서도 동일한 컨텍스트를 유지한다.  </li>\n<li><strong>추적 가능성</strong>: 요청 ID, 사용자 정보, 트랜잭션 메타데이터를 로거·DB 드라이버·외부 API 호출에 연계할 수 있다.</li>\n</ul>\n<h2 id=\"설치와-기본-설정\" style=\"position:relative;\"><a href=\"#%EC%84%A4%EC%B9%98%EC%99%80-%EA%B8%B0%EB%B3%B8-%EC%84%A4%EC%A0%95\" aria-label=\"설치와 기본 설정 permalink\" class=\"anchor-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>설치와 기본 설정</h2>\n<h3 id=\"1-nodejs-버전-확인\" style=\"position:relative;\"><a href=\"#1-nodejs-%EB%B2%84%EC%A0%84-%ED%99%95%EC%9D%B8\" aria-label=\"1 nodejs 버전 확인 permalink\" class=\"anchor-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>1. Node.js 버전 확인</h3>\n<p><code class=\"language-text\">AsyncLocalStorage</code>는 Node.js 14에서 실험적으로 도입되었으며 16 LTS 이후 안정화되었다. 최소 Node.js 18 이상을 권장한다.</p>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token function\">node</span> <span class=\"token parameter variable\">-v</span></code></pre></div>\n<h3 id=\"2-공통-로거-패키지-추가\" style=\"position:relative;\"><a href=\"#2-%EA%B3%B5%ED%86%B5-%EB%A1%9C%EA%B1%B0-%ED%8C%A8%ED%82%A4%EC%A7%80-%EC%B6%94%EA%B0%80\" aria-label=\"2 공통 로거 패키지 추가 permalink\" class=\"anchor-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>2. 공통 로거 패키지 추가</h3>\n<p>컨텍스트 연동을 위해 구조화 로깅 라이브러리를 함께 사용하는 것이 좋다. 예시는 <code class=\"language-text\">pino</code>를 사용한다.</p>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token function\">npm</span> <span class=\"token function\">install</span> pino</code></pre></div>\n<h3 id=\"3-모듈-구성\" style=\"position:relative;\"><a href=\"#3-%EB%AA%A8%EB%93%88-%EA%B5%AC%EC%84%B1\" aria-label=\"3 모듈 구성 permalink\" class=\"anchor-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>3. 모듈 구성</h3>\n<p>컨텍스트 저장소와 로거를 초기화하는 유틸리티 파일을 만든다.</p>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token comment\">// context.js</span>\n<span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> AsyncLocalStorage <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">\"node:async_hooks\"</span>\n<span class=\"token keyword\">import</span> pino <span class=\"token keyword\">from</span> <span class=\"token string\">\"pino\"</span>\n\n<span class=\"token keyword\">export</span> <span class=\"token keyword\">const</span> asyncLocalStorage <span class=\"token operator\">=</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">AsyncLocalStorage</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n<span class=\"token keyword\">export</span> <span class=\"token keyword\">const</span> logger <span class=\"token operator\">=</span> <span class=\"token function\">pino</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n\n<span class=\"token keyword\">export</span> <span class=\"token keyword\">function</span> <span class=\"token function\">withRequestContext</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">req<span class=\"token punctuation\">,</span> res<span class=\"token punctuation\">,</span> next</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> trace <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token literal-property property\">requestId</span><span class=\"token operator\">:</span> req<span class=\"token punctuation\">.</span>headers<span class=\"token punctuation\">[</span><span class=\"token string\">\"x-request-id\"</span><span class=\"token punctuation\">]</span> <span class=\"token operator\">??</span> crypto<span class=\"token punctuation\">.</span><span class=\"token function\">randomUUID</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n    <span class=\"token literal-property property\">userAgent</span><span class=\"token operator\">:</span> req<span class=\"token punctuation\">.</span>headers<span class=\"token punctuation\">[</span><span class=\"token string\">\"user-agent\"</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span>\n    <span class=\"token literal-property property\">startedAt</span><span class=\"token operator\">:</span> Date<span class=\"token punctuation\">.</span><span class=\"token function\">now</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n  <span class=\"token punctuation\">}</span>\n\n  asyncLocalStorage<span class=\"token punctuation\">.</span><span class=\"token function\">run</span><span class=\"token punctuation\">(</span>trace<span class=\"token punctuation\">,</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token function\">next</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token keyword\">export</span> <span class=\"token keyword\">function</span> <span class=\"token function\">getContext</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">return</span> asyncLocalStorage<span class=\"token punctuation\">.</span><span class=\"token function\">getStore</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<h2 id=\"코드-예시-나쁜-구현-vs-좋은-구현\" style=\"position:relative;\"><a href=\"#%EC%BD%94%EB%93%9C-%EC%98%88%EC%8B%9C-%EB%82%98%EC%81%9C-%EA%B5%AC%ED%98%84-vs-%EC%A2%8B%EC%9D%80-%EA%B5%AC%ED%98%84\" aria-label=\"코드 예시 나쁜 구현 vs 좋은 구현 permalink\" class=\"anchor-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>코드 예시: 나쁜 구현 vs 좋은 구현</h2>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token comment\">// 나쁜 예시: 응답 로거에서 req 객체를 직접 참조해 비동기 체인 밖에서 undefined가 된다.</span>\napp<span class=\"token punctuation\">.</span><span class=\"token function\">use</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">req<span class=\"token punctuation\">,</span> res<span class=\"token punctuation\">,</span> next</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  req<span class=\"token punctuation\">.</span>context <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span> <span class=\"token literal-property property\">requestId</span><span class=\"token operator\">:</span> crypto<span class=\"token punctuation\">.</span><span class=\"token function\">randomUUID</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">}</span>\n  <span class=\"token function\">next</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span>\n\n<span class=\"token function\">setImmediate</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span>req<span class=\"token punctuation\">.</span>context<span class=\"token punctuation\">.</span>requestId<span class=\"token punctuation\">)</span> <span class=\"token comment\">// TypeError 발생</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span>\n\n<span class=\"token comment\">// 좋은 예시: AsyncLocalStorage로 컨텍스트를 전파해 비동기 스케줄링 이후에도 안전하다.</span>\n<span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> asyncLocalStorage <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">\"./context.js\"</span>\n\napp<span class=\"token punctuation\">.</span><span class=\"token function\">use</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">req<span class=\"token punctuation\">,</span> res<span class=\"token punctuation\">,</span> next</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  asyncLocalStorage<span class=\"token punctuation\">.</span><span class=\"token function\">run</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span> <span class=\"token literal-property property\">requestId</span><span class=\"token operator\">:</span> crypto<span class=\"token punctuation\">.</span><span class=\"token function\">randomUUID</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token function\">next</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span>\n\n<span class=\"token function\">setImmediate</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> store <span class=\"token operator\">=</span> asyncLocalStorage<span class=\"token punctuation\">.</span><span class=\"token function\">getStore</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n  console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span>store<span class=\"token punctuation\">.</span>requestId<span class=\"token punctuation\">)</span> <span class=\"token comment\">// 정상 출력</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span></code></pre></div>\n<p>나쁜 예시는 <code class=\"language-text\">req</code> 객체를 비동기 경계 밖으로 전달하면서 컨텍스트가 끊어져 <code class=\"language-text\">TypeError</code>가 발생한다. 좋은 예시에서는 <code class=\"language-text\">AsyncLocalStorage</code>가 태스크별 스토어를 복제해 <code class=\"language-text\">setImmediate</code> 이후에도 동일한 <code class=\"language-text\">requestId</code>를 조회할 수 있다.</p>\n<h2 id=\"실무-적용-express와-fastify-통합\" style=\"position:relative;\"><a href=\"#%EC%8B%A4%EB%AC%B4-%EC%A0%81%EC%9A%A9-express%EC%99%80-fastify-%ED%86%B5%ED%95%A9\" aria-label=\"실무 적용 express와 fastify 통합 permalink\" class=\"anchor-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>실무 적용: Express와 Fastify 통합</h2>\n<h3 id=\"express-미들웨어\" style=\"position:relative;\"><a href=\"#express-%EB%AF%B8%EB%93%A4%EC%9B%A8%EC%96%B4\" aria-label=\"express 미들웨어 permalink\" class=\"anchor-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Express 미들웨어</h3>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token comment\">// app.js</span>\n<span class=\"token keyword\">import</span> express <span class=\"token keyword\">from</span> <span class=\"token string\">\"express\"</span>\n<span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> withRequestContext<span class=\"token punctuation\">,</span> getContext<span class=\"token punctuation\">,</span> logger <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">\"./context.js\"</span>\n\n<span class=\"token keyword\">const</span> app <span class=\"token operator\">=</span> <span class=\"token function\">express</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\napp<span class=\"token punctuation\">.</span><span class=\"token function\">use</span><span class=\"token punctuation\">(</span>withRequestContext<span class=\"token punctuation\">)</span>\n\napp<span class=\"token punctuation\">.</span><span class=\"token function\">get</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"/payments/:id\"</span><span class=\"token punctuation\">,</span> <span class=\"token keyword\">async</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">req<span class=\"token punctuation\">,</span> res</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> <span class=\"token punctuation\">{</span> requestId <span class=\"token punctuation\">}</span> <span class=\"token operator\">=</span> <span class=\"token function\">getContext</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n  logger<span class=\"token punctuation\">.</span><span class=\"token function\">info</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span> requestId <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"fetching payment\"</span><span class=\"token punctuation\">)</span>\n\n  <span class=\"token keyword\">const</span> payment <span class=\"token operator\">=</span> <span class=\"token keyword\">await</span> <span class=\"token function\">fetchPayment</span><span class=\"token punctuation\">(</span>req<span class=\"token punctuation\">.</span>params<span class=\"token punctuation\">.</span>id<span class=\"token punctuation\">)</span>\n  res<span class=\"token punctuation\">.</span><span class=\"token function\">json</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span> requestId<span class=\"token punctuation\">,</span> payment <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span></code></pre></div>\n<h3 id=\"fastify-플러그인\" style=\"position:relative;\"><a href=\"#fastify-%ED%94%8C%EB%9F%AC%EA%B7%B8%EC%9D%B8\" aria-label=\"fastify 플러그인 permalink\" class=\"anchor-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Fastify 플러그인</h3>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token comment\">// plugins/request-context.js</span>\n<span class=\"token keyword\">import</span> fp <span class=\"token keyword\">from</span> <span class=\"token string\">\"fastify-plugin\"</span>\n<span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> asyncLocalStorage <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">\"../context.js\"</span>\n\n<span class=\"token keyword\">export</span> <span class=\"token keyword\">default</span> <span class=\"token function\">fp</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">async</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">fastify</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  fastify<span class=\"token punctuation\">.</span><span class=\"token function\">addHook</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"onRequest\"</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">request<span class=\"token punctuation\">,</span> reply<span class=\"token punctuation\">,</span> done</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n    asyncLocalStorage<span class=\"token punctuation\">.</span><span class=\"token function\">run</span><span class=\"token punctuation\">(</span>\n      <span class=\"token punctuation\">{</span> <span class=\"token literal-property property\">requestId</span><span class=\"token operator\">:</span> request<span class=\"token punctuation\">.</span>id<span class=\"token punctuation\">,</span> <span class=\"token literal-property property\">route</span><span class=\"token operator\">:</span> request<span class=\"token punctuation\">.</span>routerPath <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n      done<span class=\"token punctuation\">,</span>\n    <span class=\"token punctuation\">)</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span>\n\n  fastify<span class=\"token punctuation\">.</span><span class=\"token function\">decorateRequest</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"requestContext\"</span><span class=\"token punctuation\">,</span> <span class=\"token keyword\">null</span><span class=\"token punctuation\">)</span>\n  fastify<span class=\"token punctuation\">.</span><span class=\"token function\">addHook</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"preHandler\"</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">request<span class=\"token punctuation\">,</span> reply<span class=\"token punctuation\">,</span> done</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n    request<span class=\"token punctuation\">.</span>requestContext <span class=\"token operator\">=</span> asyncLocalStorage<span class=\"token punctuation\">.</span><span class=\"token function\">getStore</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n    <span class=\"token function\">done</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span></code></pre></div>\n<p>Fastify에서 위 플러그인을 등록하면 서비스 레이어나 외부 연동 모듈에서 <code class=\"language-text\">asyncLocalStorage.getStore()</code>를 호출해 동일한 트레이스를 참고할 수 있다.</p>\n<h2 id=\"실무-적용-시나리오\" style=\"position:relative;\"><a href=\"#%EC%8B%A4%EB%AC%B4-%EC%A0%81%EC%9A%A9-%EC%8B%9C%EB%82%98%EB%A6%AC%EC%98%A4\" aria-label=\"실무 적용 시나리오 permalink\" class=\"anchor-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>실무 적용 시나리오</h2>\n<ol>\n<li><strong>분산 추적 연계</strong>: <code class=\"language-text\">requestId</code>를 OpenTelemetry <code class=\"language-text\">traceId</code>와 연결해 백엔드·프론트엔드 로그를 엮는다.  </li>\n<li><strong>데이터베이스 트랜잭션 묶기</strong>: Prisma, TypeORM 등의 커넥션 풀에서 컨텍스트 기반 트랜잭션을 유지한다.  </li>\n<li><strong>감사 로그 보강</strong>: 사용자 ID, 권한 정보를 컨텍스트에 저장하고 감사 로그를 자동으로 태깅한다.  </li>\n<li><strong>Feature Flag 평가</strong>: 런타임 플래그 엔진에 컨텍스트를 전달해 사용자별 실험 집단을 정확히 분류한다.</li>\n</ol>\n<h2 id=\"활용-가이드-단계별-체크리스트\" style=\"position:relative;\"><a href=\"#%ED%99%9C%EC%9A%A9-%EA%B0%80%EC%9D%B4%EB%93%9C-%EB%8B%A8%EA%B3%84%EB%B3%84-%EC%B2%B4%ED%81%AC%EB%A6%AC%EC%8A%A4%ED%8A%B8\" aria-label=\"활용 가이드 단계별 체크리스트 permalink\" class=\"anchor-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>활용 가이드: 단계별 체크리스트</h2>\n<ol>\n<li><strong>목표 정의</strong>: 로깅, 트랜잭션 제어, 실시간 모니터링 등 컨텍스트 유지 목적을 명확히 한다.  </li>\n<li><strong>컨텍스트 스키마 설계</strong>: 저장할 필드를 최소화하고 개인정보는 토큰화한다.  </li>\n<li><strong>미들웨어 일원화</strong>: 모든 요청 진입 지점에서 <code class=\"language-text\">asyncLocalStorage.run</code>을 호출해 누락을 방지한다.  </li>\n<li><strong>도구 통합</strong>: 로거, ORM, 메시지 큐 클라이언트에 컨텍스트 추출 헬퍼를 주입한다.  </li>\n<li><strong>부하 테스트</strong>: 높은 동시성에서 메모리 사용량과 이벤트 루프 지연을 모니터링한다.  </li>\n<li><strong>운영 모니터링</strong>: 컨텍스트 누수, 저장소 변형 여부를 정기적으로 검증한다.</li>\n</ol>\n<h3 id=\"선택-기준과-고려사항\" style=\"position:relative;\"><a href=\"#%EC%84%A0%ED%83%9D-%EA%B8%B0%EC%A4%80%EA%B3%BC-%EA%B3%A0%EB%A0%A4%EC%82%AC%ED%95%AD\" aria-label=\"선택 기준과 고려사항 permalink\" class=\"anchor-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>선택 기준과 고려사항</h3>\n<ul>\n<li><strong>Node.js 버전</strong>: 18 LTS 이상에서 안정적인 동작과 성능 개선을 누릴 수 있다.  </li>\n<li><strong>워크로드 특성</strong>: CPU 집약적 작업보다 I/O 중심 서비스에서 효과가 크다.  </li>\n<li><strong>보안 요건</strong>: 컨텍스트에 저장되는 민감정보는 암호화하거나 토큰화해야 한다.  </li>\n<li><strong>분산 아키텍처</strong>: 서버리스(Function-as-a-Service) 환경에서는 실행 컨텍스트 수명이 짧으므로 호출마다 초기화 전략을 수립한다.</li>\n</ul>\n<h3 id=\"주의사항과-한계\" style=\"position:relative;\"><a href=\"#%EC%A3%BC%EC%9D%98%EC%82%AC%ED%95%AD%EA%B3%BC-%ED%95%9C%EA%B3%84\" aria-label=\"주의사항과 한계 permalink\" class=\"anchor-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>주의사항과 한계</h3>\n<ul>\n<li><strong>컨텍스트 변조 위험</strong>: 개발자가 <code class=\"language-text\">getStore()</code> 반환 객체를 직접 수정하면 다른 모듈에 영향을 준다. → 깊은 복사를 사용하거나 전용 setter를 제공한다.  </li>\n<li><strong>퍼포먼스 오버헤드</strong>: 대량의 키-값을 저장하면 퍼포먼스가 저하될 수 있다. → 4~6개의 핵심 필드만 유지한다.  </li>\n<li><strong>Worker Threads</strong>: 워커 사이에 컨텍스트가 자동 공유되지 않는다. → 메시지 전송으로 수동 동기화하거나 <code class=\"language-text\">AsyncResource</code>를 활용한다.  </li>\n<li><strong>테스트 코드</strong>: Jest, Vitest 실행 시 전역 컨텍스트가 캐시될 수 있다. → 테스트 훅에서 <code class=\"language-text\">asyncLocalStorage.disable()</code>을 호출해 초기화한다.</li>\n</ul>\n<h2 id=\"faq\" style=\"position:relative;\"><a href=\"#faq\" aria-label=\"faq permalink\" class=\"anchor-header before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>FAQ</h2>\n<p><strong>Q1. 기존 CLS/continuation-local-storage 라이브러리와 무엇이 다른가?</strong><br>\nA: <code class=\"language-text\">AsyncLocalStorage</code>는 Node.js 코어가 지원해 외부 패키지보다 안정성과 성능이 높다. 기존 라이브러리는 <code class=\"language-text\">domain</code> API에 의존하고 이벤트 루프 개선 이후 호환성 문제가 발생한다.</p>\n<p><strong>Q2. 비동기 컨텍스트 내에서 비밀번호 같은 민감정보를 저장해도 안전한가?</strong><br>\nA: 메모리 내에서만 유지되지만, 프로세스 덤프나 로그에 노출될 수 있으므로 민감정보는 암호화 토큰이나 참조 ID 형태로 저장하는 것이 원칙이다.</p>\n<p><strong>Q3. 요청 한 건이 여러 서비스로 분기되면 컨텍스트가 유지되는가?</strong><br>\nA: 프로세스 내부 비동기 호출은 유지되지만, 외부 서비스 호출 후에는 컨텍스트가 전파되지 않는다. HTTP 헤더나 메시지 메타데이터로 트레이스를 전달해야 한다.</p>\n<p><strong>Q4. 고성능 환경에서 어떤 로거를 쓰는 것이 좋은가?</strong><br>\nA: <code class=\"language-text\">pino</code>, <code class=\"language-text\">winston@3</code>, <code class=\"language-text\">bunyan</code>이 대표적이며, <code class=\"language-text\">AsyncLocalStorage</code>와 함께 쓸 때는 비동기 쓰기 구조와 구조화 JSON 출력이 가능한 로거를 선택한다.</p>\n<p><strong>Q5. TypeScript 프로젝트에서는 어떻게 타입을 정의해야 하는가?</strong><br>\nA: 컨텍스트 스키마에 대한 인터페이스를 선언하고 <code class=\"language-text\">ReturnType&lt;typeof asyncLocalStorage.getStore></code>에 제네릭을 적용한다. 모듈 보강을 사용하면 <code class=\"language-text\">express.Request</code>에 <code class=\"language-text\">context</code> 필드를 안전하게 추가할 수 있다.</p>","tableOfContents":"<ul>\n<li><a href=\"/javascript/async-localstorage%EB%A1%9C-nodejs-%EB%B9%84%EB%8F%99%EA%B8%B0-%EC%BB%A8%ED%85%8D%EC%8A%A4%ED%8A%B8-%EC%B6%94%EC%A0%81%ED%95%98%EA%B8%B0/#%EA%B0%9C%EB%85%90-%EC%A0%95%EB%A6%AC-asynclocalstorage-%EC%8A%A4%EC%BD%94%ED%94%84-%EB%AA%A8%EB%8D%B8\">개념 정리: AsyncLocalStorage 스코프 모델</a></li>\n<li>\n<p><a href=\"/javascript/async-localstorage%EB%A1%9C-nodejs-%EB%B9%84%EB%8F%99%EA%B8%B0-%EC%BB%A8%ED%85%8D%EC%8A%A4%ED%8A%B8-%EC%B6%94%EC%A0%81%ED%95%98%EA%B8%B0/#%EC%84%A4%EC%B9%98%EC%99%80-%EA%B8%B0%EB%B3%B8-%EC%84%A4%EC%A0%95\">설치와 기본 설정</a></p>\n<ul>\n<li><a href=\"/javascript/async-localstorage%EB%A1%9C-nodejs-%EB%B9%84%EB%8F%99%EA%B8%B0-%EC%BB%A8%ED%85%8D%EC%8A%A4%ED%8A%B8-%EC%B6%94%EC%A0%81%ED%95%98%EA%B8%B0/#1-nodejs-%EB%B2%84%EC%A0%84-%ED%99%95%EC%9D%B8\">1. Node.js 버전 확인</a></li>\n<li><a href=\"/javascript/async-localstorage%EB%A1%9C-nodejs-%EB%B9%84%EB%8F%99%EA%B8%B0-%EC%BB%A8%ED%85%8D%EC%8A%A4%ED%8A%B8-%EC%B6%94%EC%A0%81%ED%95%98%EA%B8%B0/#2-%EA%B3%B5%ED%86%B5-%EB%A1%9C%EA%B1%B0-%ED%8C%A8%ED%82%A4%EC%A7%80-%EC%B6%94%EA%B0%80\">2. 공통 로거 패키지 추가</a></li>\n<li><a href=\"/javascript/async-localstorage%EB%A1%9C-nodejs-%EB%B9%84%EB%8F%99%EA%B8%B0-%EC%BB%A8%ED%85%8D%EC%8A%A4%ED%8A%B8-%EC%B6%94%EC%A0%81%ED%95%98%EA%B8%B0/#3-%EB%AA%A8%EB%93%88-%EA%B5%AC%EC%84%B1\">3. 모듈 구성</a></li>\n</ul>\n</li>\n<li><a href=\"/javascript/async-localstorage%EB%A1%9C-nodejs-%EB%B9%84%EB%8F%99%EA%B8%B0-%EC%BB%A8%ED%85%8D%EC%8A%A4%ED%8A%B8-%EC%B6%94%EC%A0%81%ED%95%98%EA%B8%B0/#%EC%BD%94%EB%93%9C-%EC%98%88%EC%8B%9C-%EB%82%98%EC%81%9C-%EA%B5%AC%ED%98%84-vs-%EC%A2%8B%EC%9D%80-%EA%B5%AC%ED%98%84\">코드 예시: 나쁜 구현 vs 좋은 구현</a></li>\n<li>\n<p><a href=\"/javascript/async-localstorage%EB%A1%9C-nodejs-%EB%B9%84%EB%8F%99%EA%B8%B0-%EC%BB%A8%ED%85%8D%EC%8A%A4%ED%8A%B8-%EC%B6%94%EC%A0%81%ED%95%98%EA%B8%B0/#%EC%8B%A4%EB%AC%B4-%EC%A0%81%EC%9A%A9-express%EC%99%80-fastify-%ED%86%B5%ED%95%A9\">실무 적용: Express와 Fastify 통합</a></p>\n<ul>\n<li><a href=\"/javascript/async-localstorage%EB%A1%9C-nodejs-%EB%B9%84%EB%8F%99%EA%B8%B0-%EC%BB%A8%ED%85%8D%EC%8A%A4%ED%8A%B8-%EC%B6%94%EC%A0%81%ED%95%98%EA%B8%B0/#express-%EB%AF%B8%EB%93%A4%EC%9B%A8%EC%96%B4\">Express 미들웨어</a></li>\n<li><a href=\"/javascript/async-localstorage%EB%A1%9C-nodejs-%EB%B9%84%EB%8F%99%EA%B8%B0-%EC%BB%A8%ED%85%8D%EC%8A%A4%ED%8A%B8-%EC%B6%94%EC%A0%81%ED%95%98%EA%B8%B0/#fastify-%ED%94%8C%EB%9F%AC%EA%B7%B8%EC%9D%B8\">Fastify 플러그인</a></li>\n</ul>\n</li>\n<li><a href=\"/javascript/async-localstorage%EB%A1%9C-nodejs-%EB%B9%84%EB%8F%99%EA%B8%B0-%EC%BB%A8%ED%85%8D%EC%8A%A4%ED%8A%B8-%EC%B6%94%EC%A0%81%ED%95%98%EA%B8%B0/#%EC%8B%A4%EB%AC%B4-%EC%A0%81%EC%9A%A9-%EC%8B%9C%EB%82%98%EB%A6%AC%EC%98%A4\">실무 적용 시나리오</a></li>\n<li>\n<p><a href=\"/javascript/async-localstorage%EB%A1%9C-nodejs-%EB%B9%84%EB%8F%99%EA%B8%B0-%EC%BB%A8%ED%85%8D%EC%8A%A4%ED%8A%B8-%EC%B6%94%EC%A0%81%ED%95%98%EA%B8%B0/#%ED%99%9C%EC%9A%A9-%EA%B0%80%EC%9D%B4%EB%93%9C-%EB%8B%A8%EA%B3%84%EB%B3%84-%EC%B2%B4%ED%81%AC%EB%A6%AC%EC%8A%A4%ED%8A%B8\">활용 가이드: 단계별 체크리스트</a></p>\n<ul>\n<li><a href=\"/javascript/async-localstorage%EB%A1%9C-nodejs-%EB%B9%84%EB%8F%99%EA%B8%B0-%EC%BB%A8%ED%85%8D%EC%8A%A4%ED%8A%B8-%EC%B6%94%EC%A0%81%ED%95%98%EA%B8%B0/#%EC%84%A0%ED%83%9D-%EA%B8%B0%EC%A4%80%EA%B3%BC-%EA%B3%A0%EB%A0%A4%EC%82%AC%ED%95%AD\">선택 기준과 고려사항</a></li>\n<li><a href=\"/javascript/async-localstorage%EB%A1%9C-nodejs-%EB%B9%84%EB%8F%99%EA%B8%B0-%EC%BB%A8%ED%85%8D%EC%8A%A4%ED%8A%B8-%EC%B6%94%EC%A0%81%ED%95%98%EA%B8%B0/#%EC%A3%BC%EC%9D%98%EC%82%AC%ED%95%AD%EA%B3%BC-%ED%95%9C%EA%B3%84\">주의사항과 한계</a></li>\n</ul>\n</li>\n<li><a href=\"/javascript/async-localstorage%EB%A1%9C-nodejs-%EB%B9%84%EB%8F%99%EA%B8%B0-%EC%BB%A8%ED%85%8D%EC%8A%A4%ED%8A%B8-%EC%B6%94%EC%A0%81%ED%95%98%EA%B8%B0/#faq\">FAQ</a></li>\n</ul>","wordCount":{"words":568},"fields":{"slug":"/javascript/async-localstorage로-nodejs-비동기-컨텍스트-추적하기/","image":null,"faq":[{"question":"기존 CLS/continuation-local-storage 라이브러리와 무엇이 다른가?","answer":"AsyncLocalStorage는 Node.js 코어가 지원해 외부 패키지보다 안정성과 성능이 높다. 기존 라이브러리는 domain API에 의존하고 이벤트 루프 개선 이후 호환성 문제가 발생한다."},{"question":"비동기 컨텍스트 내에서 비밀번호 같은 민감정보를 저장해도 안전한가?","answer":"메모리 내에서만 유지되지만, 프로세스 덤프나 로그에 노출될 수 있으므로 민감정보는 암호화 토큰이나 참조 ID 형태로 저장하는 것이 원칙이다."},{"question":"요청 한 건이 여러 서비스로 분기되면 컨텍스트가 유지되는가?","answer":"프로세스 내부 비동기 호출은 유지되지만, 외부 서비스 호출 후에는 컨텍스트가 전파되지 않는다. HTTP 헤더나 메시지 메타데이터로 트레이스를 전달해야 한다."},{"question":"고성능 환경에서 어떤 로거를 쓰는 것이 좋은가?","answer":"pino, winston@3, bunyan이 대표적이며, AsyncLocalStorage와 함께 쓸 때는 비동기 쓰기 구조와 구조화 JSON 출력이 가능한 로거를 선택한다."},{"question":"TypeScript 프로젝트에서는 어떻게 타입을 정의해야 하는가?","answer":"컨텍스트 스키마에 대한 인터페이스를 선언하고 ReturnType<typeof asyncLocalStorage.getStore>에 제네릭을 적용한다. 모듈 보강을 사용하면 express.Request에 context 필드를 안전하게 추가할 수 있다."}]},"frontmatter":{"title":"AsyncLocalStorage로 Node.js 비동기 컨텍스트 추적하기","date":"2025년 11월 9일","dateISO":"2025-11-09T00:00:00.000Z","updatedISO":null,"category":"javascript","description":"Node.js 20 이후의 AsyncLocalStorage로 비동기 컨텍스트를 안정적으로 추적하는 방법과 Express, Fastify 실무 적용 전략을 정리한다.","tags":["Node.js","AsyncLocalStorage","비동기","컨텍스트","로깅","트랜잭션","Observability"]}}},"pageContext":{"slug":"/javascript/async-localstorage로-nodejs-비동기-컨텍스트-추적하기/","previous":{"fields":{"slug":"/ai/AI-보안과-모델-공급망-위험-관리/"},"frontmatter":{"title":"AI 보안과 모델 공급망 위험 관리","tags":["AI 보안","모델 공급망","LLM","AI 거버넌스","Threat Modeling","Model Safety"]}},"next":{"fields":{"slug":"/ai/온디바이스-생성형-AI-프라이버시-친화형-경량-모델-설계-트렌드/"},"frontmatter":{"title":"온디바이스 생성형 AI 프라이버시 친화형 경량 모델 설계 트렌드","tags":["온디바이스 AI","생성형 AI","프라이버시","모델 최적화","엣지 컴퓨팅","TinyML","모바일 AI","개인정보보호"]}}}},"staticQueryHashes":["213619243","3262363727"]}