mulk.codes

Worker 하나로 첫 화면과 행사 페이지를 함께 내보내기

연재 · 작은 도구들 1편
  1. 01Worker 하나로 첫 화면과 행사 페이지를 함께 내보내기

왜 하나의 Worker로 묶었을까

개인 블로그는 트래픽이 불규칙하고, 글 쓰는 날보다 읽히는 날이 훨씬 많습니다. 매달 고정 비용이 나가는 VM이나 외부 DB를 붙이기보다, 이미 도메인이 물려 있는 Cloudflare Worker 안에서 모든 책임을 깔끔하게 해결하고 싶었습니다.

비용 절감의 핵심은 인스턴스를 줄이는 것이 아니라, 캐시 적중 시 DB와 스토리지를 아예 깨우지 않는 것입니다.

요청 흐름과 캐시 경계

정적 스타일시트(/s/blog.css), 어드민 Shell(/admin), 그리고 동적 SSR 페이지(/, /posts/:slug)를 같은 오리진에 두되 run_worker_first 패턴으로 경계를 나눴습니다.

TS
export async function withEdgeCache(
  request: Request,
  ctx: ExecutionContext,
  render: () => Promise<Response>
): Promise<Response> {
  const hit = await caches.default.match(request);
  if (hit) return hit;

  const res = await render();
  if (res.status === 200) {
    ctx.waitUntil(caches.default.put(request, res.clone()));
  }
  return res;
}

계층별 무료 티어 예산

계층담당 역할무료 한도 요약캐시 전략
Static AssetsCSS, JS, Admin HTML무제한 무료Immutable / ETag
Worker + Cache APISSR HTML, RSS, Sitemap일 10만 요청s-maxage=300, swr=86400
D1 (mulk-blog)글 · 연재 · 메모 · 구독일 500만 행 읽기글 저장 시 캐시 퍼지
R2 (mulk-blog-media)본문 이미지, OG 카드10GB / Egress $0immutable 1년 + ETag
기존 행사 페이지(/2026synapse)와의 격리 원칙

기존 synapse2026 D1 바인딩(DB)과 ADMIN_KEY는 건드리지 않고, 블로그 전용 BLOG_DB, BLOG_MEDIA, BLOG_ADMIN_KEY를 완전히 분리했습니다. 어드민 인증이 겹치거나 행사 데이터가 노출될 여지를 구조적으로 차단합니다.