TRENDSHIFT 딥다이브 · 2026-06-08

pg_durable 딥다이브
— 크론·큐·워커 없이, Postgres 안에서 끝까지 살아남는 워크플로

Microsoft가 공개한 PostgreSQL 확장으로, 듀러블 실행 (durable execution, 단계마다 체크포인트를 남겨 장애 후 이어 달리는 실행 모델)외부 인프라 0개로 Postgres 안에 들여놓습니다. 긴 배치 작업을 위해 cron + 작업 테이블 + 재시도 카운터 + 폴링 워커를 짜깁기하던 팀이, SQL로 워크플로 그래프를 정의하고 df.start() 한 번 부르면 — 크래시·재시작·단계 실패 후에도 마지막 체크포인트부터 재개됩니다. Rust(pgrx)로 작성됐고 Azure HorizonDB에 내장될 만큼 실전 지향입니다. (저장소: microsoft/pg_durable · Rust · TrendShift 1위(06-06) · PostgreSQL License)
목차
  1. 프로젝트 한줄 요약
  2. 왜 주목받는가
  3. 기술 스택 전체 지도
  4. 아키텍처 심화 분석
  5. 디렉토리 구조 해부
  6. 학습 포인트 (기술별)
  7. 시스템 요구사항
  8. 직접 해볼 수 있는 실습 과제
  9. 관련 기술 심화 학습 로드맵
  10. 핵심 키워드 사전
  11. 참고 링크

1프로젝트 한줄 요약

이 레포가 무엇을 하는 물건인가.

핵심 메시지

"워크플로 상태를 위해 Redis도 Temporal도 띄우지 마라.
상태는 이미 Postgres에 있다."

pg_durable 함수는 SQL 단계들의 그래프입니다. Postgres가 각 단계를 실행하며 체크포인트를 남기고, DB가 죽었다 살아나도 이미 성공한 단계는 다시 하지 않습니다. "컴퓨트를 데이터 곁으로"라는 Microsoft의 방향이 가장 구체화된 물건 중 하나.

한 줄 맛보기 — 문서 100건을 집어 처리 완료 표시하는 듀러블 함수:

SELECT df.start(
    'SELECT id FROM documents WHERE processed = false LIMIT 100' |=> 'batch'
    ~> 'UPDATE documents SET processed = true WHERE id = ANY($batch)'
);

|=>는 "결과를 batch라는 이름으로 저장", ~>는 "그다음에"라는 뜻의 합성 연산자입니다. 복사해서 돌려보면 인스턴스 ID가 돌아오고, 진행 상황은 df.instances 테이블을 SELECT하면 보입니다 — 모니터링 대시보드도 결국 SQL입니다.

2왜 주목받는가

트렌딩 이유 · 경쟁 대비 장점.

듀러블 실행은 Temporal·Step Functions가 표준으로 만든 패턴이지만, 전부 별도 오케스트레이터 서비스를 요구합니다. pg_durable의 제안은 급진적입니다 — 상태가 이미 Postgres에 있는 팀이라면, 오케스트레이터도 Postgres여야 한다. AI 파이프라인 붐(임베딩 생성→pgvector 적재 같은 행 단위 듀러블 작업 폭증)과 맞물려 06-06 트렌딩 1위에 올랐습니다.

비교 항목외부 오케스트레이터 (Temporal·Airflow)pg_durable
인프라별도 클러스터 + SDK + 콜백Postgres 확장 하나 — 추가 서비스 0
워크플로 정의Go/Java/Python 코드SQL + 합성 연산자
상태 조회전용 UI/APIdf.instances를 그냥 SELECT — 백업·권한도 DB와 동일
적합 범위다종 시스템 가로지르는 복잡 로직데이터 근처의 SQL-모양 워크플로
기존 방식의 한계
"pg_cron + 상태 컬럼 + 폴링 워커" 스파게티

긴 배치 중간에 재시작이 나면 성공한 작업을 다시 돌리고, 실패한 행 하나가 수동 정리로 번지고, 긴 트랜잭션이 락과 WAL을 키웁니다. 워크플로 로직이 SQL·워커·큐·대시보드에 흩어집니다.

이 레포의 해결
체크포인트·재시도·진행 추적을 전부 DB 안으로

각 단계가 듀러블하게 기록되니 재시작은 "이어하기"가 되고, 앱 계층의 워커·큐 소비자·스케줄러 글루가 통째로 사라질 수 있습니다. README가 "언제 쓰지 말아야 하나"(단일 SQL이면 과잉, 서브밀리초 응답엔 부적합, 확장 설치 불가 환경 등)까지 명시하는 점도 신뢰 포인트.

3기술 스택 전체 지도

Rust로 짠 Postgres 확장 — pgrx 생태계의 대형 실례.

레이어기술역할
확장 본체Rust + pgrx 0.16Postgres 확장을 Rust로 작성하는 프레임워크 — C 대신 안전한 Rust로 cdylib 빌드.
지원 버전PostgreSQL 17·18 (공식), 13~16 feature 플래그shared_preload_libraries 등록 + CREATE EXTENSION.
실행 엔진오케스트레이션/액티비티 분리 (duroxide 계열 모델)워크플로 그래프 해석은 orchestrations/, 실제 일은 activities/.
백그라운드 워커Postgres BGWDB 프로세스 안에서 단계를 집어 실행 — 외부 워커 불필요.
DSLsrc/dsl.rs — ~>·|=> 연산자SQL 문자열 합성으로 그래프 정의. 문법은 docs/grammar.md.
HTTP 단계df.http() + src/ssrf.rs외부 API 호출 단계 — SSRF 가드와 도메인 허용목록(feature로 제어)이 내장.
배포deb 패키지·Docker·devcontainerPG 17/18용 패키지 자동 릴리스. Azure HorizonDB에 기본 탑재.
용어
pgrx (Postgres extension framework in Rust)
Postgres 확장은 전통적으로 C로 짰지만, pgrx는 Rust로 짜게 해 줍니다 — 메모리 안전성과 풍부한 크레이트 생태계를 확장 개발에 들여온 프레임워크. pg_durable은 그 대형 실전 사례입니다.

4아키텍처 심화 분석

df.start() 한 번이 거치는 길.

pg_durable 실행 구조 (전부 Postgres 안) ┌─────────────────────────────────────────────────────┐ │ SELECT df.start('q1' |=> 'batch' ~> 'q2'); │ │ │ │ │ ▼ │ │ ① dsl.rs ── 연산자 식을 함수 그래프로 파싱 │ │ │ (노드=SQL/HTTP 단계, 간선=의존) │ │ ▼ │ │ ② 인스턴스 생성 ── df.instances에 기록, ID 반환 │ │ │ │ │ ▼ │ │ ③ 백그라운드 워커(worker.rs) │ │ │ orchestrations/execute_function_graph.rs │ │ │ 가 그래프를 돌며 실행 가능한 노드 선별 │ │ ▼ │ │ ④ activities/ ── 단계 실행 │ │ │ execute_sql / execute_http(SSRF 가드) │ │ │ update_node_status (단계마다 체크포인트!) │ │ ▼ │ │ ⑤ 완료/실패 ── update_instance_status │ │ │ │ ⚡ 크래시? → 재시작 후 ③이 체크포인트를 읽고 │ │ 미완료 노드부터 이어 실행 (성공한 단계는 재실행 안 함) │ └─────────────────────────────────────────────────────┘

구조의 핵심은 오케스트레이션과 액티비티의 분리입니다 — Temporal과 같은 사상인데 무대만 DB 안입니다. 오케스트레이터(그래프 진행 결정)는 결정적이어야 하고, 부수효과 있는 일(SQL 실행·HTTP 호출)은 전부 액티비티로 격리돼 각각 체크포인트를 가집니다. 덕분에 재개 시 "어디까지 했는지"가 모호하지 않습니다. 병렬 fan-out(독립 쿼리 여러 개 동시 실행 후 join)도 그래프 표현으로 자연스럽게 풀립니다.

또 하나 눈여겨볼 것은 src/ssrf.rs — DB 안에서 HTTP를 쏘는 기능은 SSRF (Server-Side Request Forgery, 서버가 내부망으로 요청을 쏘게 속이는 공격)의 통로가 되기 쉬운데, 도메인 허용목록을 컴파일 타임 feature(http-allow-azure-domains 등)로 강제합니다. "편의 기능엔 반드시 보안 가드"의 모범입니다.

비유

게임의 세이브 포인트와 같습니다. 보스전(긴 배치) 중간중간 자동 저장되니, 게임이 꺼져도(DB 크래시) 처음부터가 아니라 마지막 세이브에서 이어 합니다. pg_durable은 그 세이브 파일을 게임기 본체(Postgres) 안에 저장하는 방식이고, Temporal은 별도의 클라우드 세이브 서버를 두는 방식입니다.

5디렉토리 구조 해부

어떤 폴더가 무슨 일을 하나.

pg_durable/ ├── src/ │ ├── lib.rs 확장 진입점 (pgrx 매크로) │ ├── dsl.rs ~> |=> 연산자 → 그래프 파싱 ★ │ ├── worker.rs 백그라운드 워커 │ ├── orchestrations/ │ │ └── execute_function_graph.rs 그래프 진행 결정 │ ├── activities/ 부수효과 격리 계층 ★ │ │ ├── execute_sql.rs · execute_http.rs │ │ └── update_node_status.rs (체크포인트) │ ├── ssrf.rs HTTP 보안 가드 │ ├── client.rs·registry.rs·monitoring.rs·types.rs ├── docs/ 설계 문서가 유난히 풍부 ★ │ ├── ARCHITECTURE.md · pg_durable_spec.md · grammar.md │ ├── DUROXIDE_PG_DEADLOCK_ISSUE.md 데드락 사후 분석 │ └── http-security.md · multi-database.md … ├── .agents/skills/pg-durable-sql/SKILL.md 에이전트 스킬! ├── Dockerfile·docker-compose.yml·devcontainer └── USER_GUIDE.md·Makefile
위치주목할 점
docs/스펙·문법·보안·데드락 이슈 분석까지 — 설계 결정의 이유가 문서로 남는 MS 스타일.
src/activities/듀러블 실행의 본질(부수효과 격리 + 체크포인트)이 파일 구조로 드러남.
.agents/skills/DB 확장에도 에이전트 스킬 동봉 — "AI가 pg_durable SQL을 짜게" 하려는 포석.
docs/DUROXIDE_PG_DEADLOCK_ISSUE.md실제로 만난 데드락의 해부 — 분산 시스템 디버깅 읽을거리로 수준급.

6학습 포인트 (기술별)

이 레포에서 배울 만한 것 + 어디를 보면 되는지.

포인트 1 — 분산 시스템

듀러블 실행 패턴의 최소 구현

오케스트레이션(결정적)/액티비티(부수효과) 분리, 단계별 체크포인트, 재개 의미론 — Temporal 문서로 배우면 추상적인 개념이 여기선 파일 몇 개의 Rust로 만져집니다.

포인트 2 — Postgres 내부

pgrx로 확장 만들기 + 백그라운드 워커

shared_preload_libraries, BGW 생명주기, 확장 업그레이드 스크립트(extension_lifecycle.md) — Postgres 확장 개발의 실무 전 과정을 한 레포에서 봅니다.

포인트 3 — DSL 설계

SQL 위에 합성 연산자 얹기

~>(순차)·|=>(이름 붙은 결과)라는 두 연산자로 그래프를 표현하는 절제된 DSL — grammar.md와 dsl.rs를 대조하며 "작은 문법"의 설계를 배울 수 있습니다.

포인트 4 — 보안

DB발 HTTP의 SSRF 방어를 컴파일 타임에

허용 도메인을 런타임 설정이 아니라 빌드 feature로 박는 선택(http-allow-azure-domains) — "설정 실수로 열리는 구멍"을 빌드 단계에서 봉쇄하는 접근입니다.

7시스템 요구사항

돌리려면 무엇이 필요한가.

항목요구사항
PostgreSQL17 또는 18 (공식 패키지 기준) — deb 패키지는 amd64.
설치패키지 설치 → shared_preload_libraries에 pg_durable 추가 → 재시작 → CREATE EXTENSION.
개발 빌드Rust + pgrx 툴체인. devcontainer/docker-compose 제공으로 진입장벽 낮음.
매니지드 환경확장 설치 권한 필요 — 불가 환경이면 Azure HorizonDB(기본 탑재) 같은 옵션.

8직접 해볼 수 있는 실습 과제

난이도별로 손에 익히는 단계.

실습 1

docker-compose로 첫 듀러블 함수 난이도 ★☆☆ 입문

레포의 compose를 띄우고 README의 Quick Example을 실행 → SELECT * FROM df.instances로 인스턴스 상태를 관찰합니다.

실습 2

크래시 생존 실험 난이도 ★★☆ 중급

일부러 느린 다단계 워크플로(pg_sleep 끼운 3단계)를 시작하고 중간에 컨테이너를 죽였다 살려, 어느 단계부터 재개되는지 df 테이블로 추적합니다 — 듀러블 실행의 핵심 가치를 몸으로 확인.

실습 3

fan-out 집계 그래프 난이도 ★★☆ 중급

독립 쿼리 3개(사용자 수·주문 수·매출 합)를 병렬 실행 후 join하는 README의 대시보드 시나리오를 직접 작성해 봅니다 — 그래프 표현력 연습.

실습 4

임베딩 파이프라인 시제품 난이도 ★★★ 고급

문서 청크 → df.http()로 임베딩 API 호출 → pgvector upsert의 행 단위 듀러블 파이프라인을 만들고, API가 간헐 실패할 때 재시도가 어떻게 동작하는지 관찰합니다.

9관련 기술 심화 학습 로드맵

한 주씩 따라가는 계획.

주차주제학습 자료
1주차듀러블 실행 개념 + Quick ExampleREADME · USER_GUIDE.md
2주차DSL 문법과 그래프 모델docs/grammar.md · docs/SCENARIOS.md
3주차아키텍처 — 오케스트레이션/액티비티/워커docs/ARCHITECTURE.md · src/ 정독
4주차pgrx 확장 개발 입문pgrx 공식 튜토리얼 · build.rs
5주차비교 연구 — Temporal·DBOS·pg_cron과의 트레이드오프각 프로젝트 문서 · 실습 2·4

10핵심 키워드 사전

본문에 나온 용어 빠른 참조.

용어의미
듀러블 실행단계마다 상태를 영속화해 장애 후 이어 달리는 실행 모델.
체크포인트"여기까지 성공"을 기록한 지점 — 재개의 기준.
오케스트레이션 / 액티비티진행 결정(결정적) / 실제 부수효과 작업 — 듀러블 실행의 표준 분리.
~> / |=>pg_durable DSL — 순차 연결 / 결과에 이름 붙이기.
df.instances실행 중·완료된 워크플로 인스턴스를 담는 테이블 — SQL로 모니터링.
백그라운드 워커(BGW)Postgres 안에서 도는 상주 프로세스 — 외부 워커를 대체.
pgrxRust로 Postgres 확장을 만드는 프레임워크.
SSRF서버를 속여 내부망으로 요청을 쏘게 하는 공격 — df.http()의 도메인 가드 이유.
shared_preload_librariesPostgres 시작 시 로드할 라이브러리 목록 — BGW 쓰는 확장의 필수 등록처.
fan-out독립 작업 여러 개를 병렬로 펼쳤다 합치는 패턴.

11참고 링크