pg_durable - PostgreSQL을 위한 내구성 SQL 함수
(github.com/microsoft)- PostgreSQL 내부에서 재시도, 스케줄링, 병렬 fan-out, 조건 분기를 작은 SQL DSL만으로 처리하는 durable function 확장
- 컨테이너나 외부 서비스 없이 Postgres와 백그라운드 워커만으로 동작
- 모든 단계가 PostgreSQL에 상태를 체크포인트로 기록해 크래시·재시작·연결 끊김에도 중단 지점부터 재개
- 큐 관리, 상태 추적, 크래시 복구, 단계 조정, 재시도를 직접 구현할 필요 없이 SQL만 작성하면 오케스트레이션 엔진이 처리
- 직접 구현 시 300줄 이상의 보일러플레이트가 필요한 작업을 단일 DSL 호출로 대체, PostgreSQL 17에서 오픈소스로 즉시 사용 가능
개요와 핵심 가치
- Postgres에 내장된 크래시 방지(crash-proof) durable function으로, 재시도·스케줄링·병렬 fan-out·조건 분기를 작은 SQL DSL로 오케스트레이션
- 추가 인프라 없이 Postgres + 백그라운드 워커만으로 동작, 별도 컨테이너나 외부 서비스 불필요
- 큐 관리·상태 추적·크래시 복구·단계 조정·재시도를 모두 담당하는 오케스트레이션 엔진 역할, 사용자는 SQL만 작성
pg_durable 없이 구현할 경우
- 3개 집계를 병렬 실행 후 대시보드를 갱신하면서 재시도와 크래시 복구까지 넣으려면 300줄 이상의 보일러플레이트 필요
- 직접 구축해야 하는 항목: 큐 설정 및 구성, 워커 관리 및 폴링, 메시지 처리 및 상태 추적, 에러 처리 및 재시도, 수동 단계 조정
- 예시 코드에는
job_queue,job_results,job_state,workflow_steps,step_variables,scheduled_jobs등 다수의 상태 테이블과 폴링 워커, 워크플로 진행, 크래시 복구, 병렬 실행 코디네이터, 변수 전달, 스케줄링, 정리 함수가 포함 - 스케줄링의
next_run계산에는 외부 cron 파서 라이브러리가 추가로 요구됨
pg_durable로 구현할 경우
- 동일한 병렬 집계 + 대시보드 갱신을 단일
df.start()호출로 표현,&연산자로 fan-out 후~>로 join 처리- 예: 3개 쿼리가 병렬로 분기된 뒤
refresh dashboard단계로 합류해 결과 생성 - 라이브 실행 예시에서 3단계 병렬 실행 후 join → dashboard ready까지 1.9초만에 durable하게 완료
- 예: 3개 쿼리가 병렬로 분기된 뒤
- 큐 관리, 상태 추적, 크래시 복구, 단계 조정, 재시도를 모두 pg_durable이 처리
주요 특징
-
Durable by default
- 모든 단계가 PostgreSQL에 상태를 체크포인트로 기록, 크래시·재시작·연결 끊김에도 워크플로 생존
- 중단된 지점에서 정확히 그대로 재개
-
Automatic retries
- flaky 작업을 위한 재시도 로직 내장, 단계 실패 시 해당 단계만 재시도되고 나머지 워크플로는 계속 진행
- 수동 에러 처리 코드 불필요
-
Full observability in SQL
- 모든 워크플로 상태가 Postgres 테이블에 저장, 실행 이력 조회·단계 출력 확인·실패 디버깅을 표준 SQL로 수행
- 외부 대시보드 불필요
-
Parallel execution
&연산자 또는df.join()으로 독립 작업을 fan-out, 집계·API 호출·ETL 단계를 자동 조정과 함께 동시 실행
만들 수 있는 패턴
-
ETL Pipelines
- cleanup → transform → load를 순차 보장과 함께 연결, 각 단계가 이전 단계를 대기하고 실패 시 파이프라인을 깔끔히 중단 (
~> sequence,|=> variables)
- cleanup → transform → load를 순차 보장과 함께 연결, 각 단계가 이전 단계를 대기하고 실패 시 파이프라인을 깔끔히 중단 (
-
Parallel Aggregation
- 사용자 수 집계 + 매출 합산 + 재고 확인을 동시에 수행, 여러 쿼리로 fan-out 후 전체 완료 대기 (
&,df.join())
- 사용자 수 집계 + 매출 합산 + 재고 확인을 동시에 수행, 여러 쿼리로 fan-out 후 전체 완료 대기 (
-
Order Processing
- 주문 ID를 캡처해 검증·처리·완료 단계로 전달, 단계 간 변수가 자동 흐름 (
|=> capture,$var substitution,df.sleep())
- 주문 ID를 캡처해 검증·처리·완료 단계로 전달, 단계 간 변수가 자동 흐름 (
-
Scheduled Jobs
- cron 스케줄로 API 폴링·레코드 아카이브·데이터 동기화, 루프가 영구 실행되며 재시작에도 생존 (
@> loop,df.wait_for_schedule())
- cron 스케줄로 API 폴링·레코드 아카이브·데이터 동기화, 루프가 영구 실행되며 재시작에도 생존 (
-
Conditional Branching
- 대기 작업·행 수·플래그를 확인해 처리 또는 건너뛰기 분기, 분기 로직이 애플리케이션이 아닌 SQL에 위치 (
df.if(),?> conditional)
- 대기 작업·행 수·플래그를 확인해 처리 또는 건너뛰기 분기, 분기 로직이 애플리케이션이 아닌 SQL에 위치 (
-
Multi-step Validation
- 데이터 가져오기 → 스키마 검증 → 비즈니스 규칙 확인 → 승인/거부, 각 단계가 체크포인트되어 실패해도 진행 상황 유실 없음
-
Database Maintenance
- autovacuum 차단 요소·테이블 bloat·wraparound 위험을 탐지해 검토용으로 노출, 승인 대기 후 재시작에도 durable하게 교정 (
?> conditional,df.wait_for_signal(),@> loop)
- autovacuum 차단 요소·테이블 bloat·wraparound 위험을 탐지해 검토용으로 노출, 승인 대기 후 재시작에도 durable하게 교정 (
-
Azure Functions & HTTP
df.http()로 Azure Functions나 허용된 HTTPS 엔드포인트를 SQL에서 직접 호출, 문서 청킹·행 보강·레코드 분류를 인라인 처리
-
Human-in-the-Loop Approval
- 일상 작업은 자동 승인하고 고위험 작업(대형 청구서, 파괴적 작업)은 사람의 승인 신호 전까지 일시 정지 (
df.wait_for_signal(),df.if())
- 일상 작업은 자동 승인하고 고위험 작업(대형 청구서, 파괴적 작업)은 사람의 승인 신호 전까지 일시 정지 (
AI 기반 작성 지원
- 워크플로를 평문 영어로 설명하면 Copilot이 올바른 durable-function SQL을 생성, 문법 학습 없이 원하는 내용만 기술
- 저장소에 재사용 가능한 에이전트 스킬
pg-durable-sql포함, GitHub Copilot 및 기타 에이전트에 연산자·변수 치환·루프·병렬 join 등 올바른 SQL 생성법을 학습시킴
오픈소스 제공
- 대기 명단·락인 없이 완전 오픈소스로 제공, 저장소를 클론·빌드해 자신의 PostgreSQL에서 즉시 실행
- 노트북·서버·클라우드 어디서나 durable orchestration을 적용 가능
Azure HorizonDB 매니지드 옵션
- Azure HorizonDB는 Microsoft의 새 PostgreSQL 클라우드 서비스로, pg_durable이 내장되어 작성한 durable function을 그대로 유지하면서 엔터프라이즈 확장·보안·AI 추가
- 최대 3× 빠른 성능, 스토리지 자동 확장 최대 128 TB, 컴퓨트 스케일아웃 최대 3,072 vCore
- Microsoft Defender 실시간 위협 탐지, Microsoft Entra ID 신원 관리
- Filtered DiskANN 벡터 검색, 시맨틱 랭킹, 인데이터베이스 AI 모델 큐레이션
- Microsoft Fabric 근실시간 미러링, VS Code 통합, GitHub Copilot 연계
-
내장 AI 파이프라인
- HorizonDB가 pg_durable의 durable 실행 위에 매니지드 엔드투엔드 AI 파이프라인을 계층화, 각 단계가 체크포인트·재시도·크래시 안전
- 단계 흐름: Ingest(문서·데이터 로드) → Chunk(콘텐츠 분할) → Embed(벡터화) → Index(DiskANN 저장) → Serve(검색·랭킹)
댓글과 토론
Hacker News 의견들
-
2026년은 Postgres 큐의 해가 될 듯함: DBOS[0], pgQue[1] 같은 흐름이 있고, 커뮤니티가 이런 선택지를 만들어 주는 건 멋짐
다만 전직 애플리케이션 엔지니어 입장에서는 큐 로직이 코드와 Git 안에 있는 편을 선호함. 적절한 도구가 있으면 생각이 바뀔 수도 있음
[0]: https://www.dbos.dev/
[1]: https://github.com/NikolayS/pgque- 작업 방식이 더 어렵거나 그냥 다른 것일 수도 있지만, 문서·검색 가능한 글·경험·도구가 부족해 보임
버전 관리, 디버깅, 테스트, 릴리스는 어떻게 하는지 궁금함. 데이터 지역성과 스택 단순화를 위해 전부 한곳에 두는 건 좋아 보이지만, “제대로” 하는 방법에 대한 유용한 지식을 많이 잃는 느낌임 - “큐 로직은 코드에 두고 싶다”에 동의함. 데이터 자체보다 그 데이터에 대해 수행해야 하는 동작이 훨씬 자주 바뀌는데, 동작을 바꿀 때마다 마이그레이션을 해야 하는 건 이해가 안 됨
Supabase에서 조금만 복잡한 일을 하려 해도 Postgres 함수를 만들어야 했던 점도 그래서 정말 싫었음. 다만 이전 스타트업에서는 Postgres 위에 간단한 작업 큐를 직접 만들었고, pgQue 같은 것이 있었다면 훨씬 다듬어진 형태가 됐을 것 같음 - Postgres 7 시절부터 팬이었고 실험적으로 가능한 한 많은 걸 PostgreSQL 안에 넣어 보려 했지만, 최소한 개발자 경험과 관측성은 아직 부족함
멀티 마스터 확장도 즉시 쓸 수 있고 완전히 안전한 이야기는 아니라서, 데이터베이스 확장 필요성을 앞당기는 쓰기 중심의 복잡한 작업을 넣는 데는 조심스러움 - DB 트리거가 있던 프로젝트에서는 SQL 코드도 Git에 넣어 관리했음
로컬 설정 시 트리거가 로컬 데이터베이스에 들어가도록 Django 마이그레이션에 밀어 넣은 경우도 있었음
- 작업 방식이 더 어렵거나 그냥 다른 것일 수도 있지만, 문서·검색 가능한 글·경험·도구가 부족해 보임
-
이건 저장 프로시저 냄새가 남. 단위 테스트도, 버전 관리도 어렵고, 비즈니스 로직이 데이터베이스 안에 숨어 “숨은 두뇌”가 됨
시끄러운 워크로드를 격리하기도 어렵고, 관측성도 없으며, 확장 압력이 전부 Postgres에 몰림. 특히 API 호출 같은 입출력이 부족함. 로컬 데이터베이스 안에서만 도는 작업에는 괜찮지만, 쓰임새가 좁아 보임- 저장 프로시저도 제대로 쓰면 훌륭함. 버전 관리는 단조 증가하는 ID를 이름 끝에 붙이면 되고, 깨지는 변경이 필요할 때 ID를 올리며, 예전 버전은 더 이상 쓰지 않을 때까지 남겨 두면 됨
물론 데이터베이스 업그레이드 절차가 제대로 있어야 함. 팀원이 root로 임의 SQL 마이그레이션을 실행하는 식이면 고생하게 됨
단위 테스트도 다른 SQL 테스트와 똑같이 가능하고, 데이터베이스를 띄워야 할 뿐임. 저장 프로시저를 테스트할 수 없다면 SQL 자체를 테스트할 방법이 없다는 뜻이고, 그게 진짜 문제임
저장 프로시저의 대안은 데이터베이스에 비즈니스 로직을 전혀 안 두는 것이 아니라, 코드베이스 곳곳에 SQL이 흩어져 테스트하기 어렵고 버전 관리와 캡슐화가 나쁘며 불필요하게 느린 상태가 되는 경우가 많음
관측성은 일부 맞는 말로, SQL 문제를 들여다보는 일은 대부분의 프로그래밍 언어보다 손이 더 감. 하지만 저장 프로시저가 입출력 문제와 확장 문제를 만든다면 잘못 쓰고 있는 것이고, 제대로 쓰면 오히려 입출력을 크게 줄여 확장성을 개선하는 경우가 많음
- 저장 프로시저도 제대로 쓰면 훌륭함. 버전 관리는 단조 증가하는 ID를 이름 끝에 붙이면 되고, 깨지는 변경이 필요할 때 ID를 올리며, 예전 버전은 더 이상 쓰지 않을 때까지 남겨 두면 됨
-
제대로 이해한 게 맞다면, Pi LLM harness 개발자들이 만든 Absurd는 순수 데이터베이스 접근을 가능한 한 줄이는 쪽으로 보임. 아직 이 주제를 막 보기 시작한 상태임
https://github.com/earendil-works/absurd- 사소한 정정이지만, absurd는 Mario Zechner가 earendil에 합류하기 전부터 시작된 earendil의 원래 프로젝트처럼 보이고, 커밋에서도 그를 보지 못했음
물론 세부 사정을 전부 아는 건 아니라 진심으로 궁금함
- 사소한 정정이지만, absurd는 Mario Zechner가 earendil에 합류하기 전부터 시작된 earendil의 원래 프로젝트처럼 보이고, 커밋에서도 그를 보지 못했음
-
“쓰지 말아야 할 때”에 “워크플로가 대부분 Postgres 밖에 있고 여러 이기종 시스템에 걸쳐 있을 때”라고 되어 있는데, 그렇다면 이 프로젝트가 Temporal 같은 것과 어떻게 비교될 수 있는지 모르겠음
이 권고가 암시하는 제한을 잘못 이해한 것인지 궁금함- 동의함. 예제인 https://github.com/microsoft/pg_durable/blob/main/examples/i...를 보면 프로젝트의 가치가 잘 이해되지 않음
기술적으로는 흥미로운 성취일 수 있지만, 이런 SQL을 읽는 건 꽤 기묘함
SELECT df.start(
@> (
($$SELECT ... FROM demo.invoices WHERE status = 'pending'$$ |=> 'inv')
~> df.if_rows('inv',
$$UPDATE ... SET status = 'processing'$$
~> (df.http(...) |=> 'resp')
~> df.if($$SELECT $r.ok$$,
-- classify, branch, wait for signal ...
),
df.sleep(5)
)
),
'invoice-approval-pipeline'
);
- 동의함. 예제인 https://github.com/microsoft/pg_durable/blob/main/examples/i...를 보면 프로젝트의 가치가 잘 이해되지 않음
-
회사에서 Azure에 묶여 있는데, Azure PostgreSQL이 현대적인 기능을 따라잡기를 계속 기다리는 중임
예를 들어 이걸 쓸 수 없음: https://www.paradedb.com/blog/hybrid-search-in-postgresql-th...
초광폭 고차원 벡터도 지원되지 않음. pg_durable을 오픈소스로 내는 건 좋지만, AWS에서 당연히 받을 수 있는 기본 기능부터 도입하면 어떨까 싶음- ParadeDB는 AGPL이라 대형 클라우드 사업자들에서 일반적으로 제공되기 어려움. 다만 Azure HorizonDB에서는 https://github.com/timescale/pg_textsearch를 쓸 수 있고, Flex에도 곧 들어갈 가능성이 큼
공개하자면 pg_textsearch 유지관리자이고 지금은 Azure에 있음. 벡터 지원에 대한 말은 정확히 이해하지 못했는데, Azure에서 제공되는 pgvector + diskann을 넘어서는 뭔가를 원하는 것인지 궁금함 - 벡터 검색에는 Azure Cosmos DB가 더 맞지 않나 싶음
- 이미 검토했겠지만, 그냥 베어 VM을 만들고 최신 Postgres를 설치하면 안 되는 이유가 궁금함
- Azure PG 팀에서 Postgres의 AI 기능을 맡는 PM임. 요청한 기능들은 실제로 제공 중이고, 지난 3~6개월 사이에 많은 진전이 있었음
하이브리드 검색(BM25 + 벡터)의 경우 ParadeDB의 pg_search도 AWS 네이티브 기능은 아니며 EC2에 직접 호스팅해야 함. Azure PostgreSQL에는 같은 BM25 순위 모델을 제공하는 pg_textsearch를 네이티브로 만들었고, 주 기여자가 현재 Azure Postgres 팀에 있음
문서: https://learn.microsoft.com/en-us/azure/horizondb/ai/full-te...
고차원 벡터는 오히려 앞서 있는 영역임. HNSW를 쓰는 pgvector는 2,000차원 제한이 있지만, Azure는 벡터 저장과 검색용 pgvector를 지원하고, 고차원·대규모 워크로드에는 Microsoft의 그래프 기반 벡터 인덱스인 pg_diskann을 제공함. 최대 16,000차원을 지원하고, 그래프 순회 중 WHERE 조건을 평가하는 고급 인덱스 내 필터링도 제공해 선택적 조건에서 재현율을 잃지 않음
pgvector: https://learn.microsoft.com/en-us/azure/horizondb/ai/vector-...
DiskANN 고차원 지원: https://learn.microsoft.com/en-us/azure/horizondb/ai/vector-...
이 기능들은 현재 Azure PostgreSQL, 특히 Azure HorizonDB Preview에서 사용 가능함. 특정 워크로드가 있다면 더 구체적으로 살펴볼 수 있음
- ParadeDB는 AGPL이라 대형 클라우드 사업자들에서 일반적으로 제공되기 어려움. 다만 Azure HorizonDB에서는 https://github.com/timescale/pg_textsearch를 쓸 수 있고, Flex에도 곧 들어갈 가능성이 큼
-
이건 Apache Airflow 같은 DAG 스케줄러가 오래전부터 풀어 온 오래된 문제에 대한 잘못된 해법처럼 느껴짐
제어 흐름을 왜 코드가 아니라 데이터베이스에 저장하고 싶은지 이상함. 프로젝트를 깎아내리려는 건 아니고, 아직 잘 이해가 안 됨- Microsoft에는 이런 용도의 Durable Task 프레임워크[1]가 있고, Temporal처럼 자체 호스팅 독립 서비스로도 실행할 수 있으며 Azure Functions에서 서버리스로도 돌릴 수 있음. 기억이 맞다면 Airflow, Temporal보다도 먼저 나왔음
이 프로젝트는 더 데이터베이스 특화 사용 사례로 보임. 장점은 워크플로 로그와 코드베이스를 대조하며 한 줄씩 추적하지 않아도, 작업의 정확한 상태를 데이터베이스 자체에서 추적할 수 있다는 점일 듯함. 부하와 지연도 더 작고, 운영상 띄워야 할 구성요소가 하나 줄어드는 효과도 있을 것 같음
[1] https://learn.microsoft.com/en-us/azure/durable-task/common/... - Airflow 같은 외부 도구는 데이터베이스 부하를 알 수 없음. 개발자가 동시 워커 200개를 데이터베이스에 때려 넣으면 다른 워크로드가 영향을 받을 수 있음
반대로 이 방식은 현재 그렇게 동작하는 것 같지는 않지만, 왕복 지연 비용 없이 거의 실시간 성능 피드백을 받아 스스로 조절할 가능성이 있음
- Microsoft에는 이런 용도의 Durable Task 프레임워크[1]가 있고, Temporal처럼 자체 호스팅 독립 서비스로도 실행할 수 있으며 Azure Functions에서 서버리스로도 돌릴 수 있음. 기억이 맞다면 Airflow, Temporal보다도 먼저 나왔음
-
문서와 예제를 읽어도 몇 가지가 명확하지 않음.
df.wait_for_schedule()는 어떻게 동작하는지 궁금함
애플리케이션에서 호출하면 멱등적인지, 같은 파라미터로 두 번 실행하면 틱이 두 번 발생하는지, 쿼리 콘솔에서 한 번만 수동으로 호출하는 것인지, 마이그레이션 스크립트 일부로 실행하는 것인지 모르겠음
예제[0]의timed_out은 시간 초과 시 반환되는 고정 상수인지도 궁금함. 오류나 예외 처리는 어떻게 하는지도 바로 보이지 않음
[0] https://github.com/microsoft/pg_durable/blob/main/examples/i...df.start()를 호출하면 내구성 함수를 만들고 동시에 실행을 시작함. 이 호출은 해당 실행을 나타내는 인스턴스 ID를 돌려주고, 이후 그 실행을 참조하는 데 쓸 수 있음
이 내구성 함수 안에서df.wait_for_signal()을 호출하는데, 이 호출은 해당 함수 인스턴스 안에서 정확히 한 번만 실행되므로 중복은 불가능함.df.start()호출 자체가 시간 초과되어 다시 실행되면 중복될 수 있지만, 그 경우에는 다른 함수 인스턴스가 만들어짐
SQL 실행 중 처리되지 않은 오류가 나면 함수 인스턴스는 실패하고, 상태에는 발생한 정확한 오류가 그대로 올라옴
-
데이터베이스 밖에 있는 오케스트레이션 도구 대신 이걸 왜 써야 하는지 설명해 줄 수 있을까. README와 예제를 읽어도 아직 이해가 안 됨
- 데이터베이스의 스냅샷 PITR을 쓰면 특정 시점의 내구성 작업까지 전부 함께 복원됨
같은 데이터 저장소에 속한 다른 구성요소와 백업을 동기화할 필요가 없어서 ETL 파이프라인이나 상태 기계형 작업에 좋음. ETL이 대부분 SQL이라면 실제 작업이 같은 서버에서 실행되는 것도 도움이 됨 - 기여자 입장에서 보면 Microsoft의 Postgres 고객은 꽤 균등하게 두 부류로 나뉨. 가능한 한 많은 걸 데이터베이스 안에서 하려는 쪽과, 애플리케이션과 연산을 데이터베이스 밖에 두고 싶어 하는 쪽임
- 아키텍처에서 데이터베이스가 유일한 상태 저장 구성요소라면 때때로 편리함
모든 상태가 한 데이터베이스에 있으면 일관된 백업을 얻을 가능성도 더 높음 - 애플리케이션 워크플로를 잘 통합할 수 있음. 예를 들어 프런트엔드 앱의 고정 링크에서 진행 상황을 보여 주는 식이 가능하고, 앱 재시작에도 이어서 실행되는 워크플로를 만들 수 있으며, 인프라 구성요소를 하나 더 추가하지 않아도 됨
https://transport.data.gouv.fr에서 Postgres를 그런 용도로 쓰고 있고, 꽤 많은 처리를 하는 Elixir 앱에서 도움이 됨. pg_durable은 아직 잘 모르지만 비슷한 해법을 쓰거나 구현해 본 적이 있어서 공감됨
- 데이터베이스의 스냅샷 PITR을 쓰면 특정 시점의 내구성 작업까지 전부 함께 복원됨
-
데이터베이스는 이미 확장하기 가장 어려운 인프라 중 하나 아닌가. 왜 거기에 장시간 실행 작업까지 얹고 싶은지 모르겠음
- Postgres에서 장시간 실행 작업을 돌리는 건 전혀 새로운 일이 아님. 예로 pg_cron이 있음
결국 이런 워크로드는 외부 구성요소가 트리거하든 아니든 데이터베이스를 상대로 실행될 작업임. 데이터나 AI 파이프라인에서 추가 구성요소로 인한 왕복과 실패 지점을 피하려고 데이터베이스에서 HTTP 쿼리를 보내는 방식도 더 흔해졌음. 다만 연산을 데이터 쪽으로 가져갈지, 데이터를 연산 쪽으로 가져갈지는 논쟁이 큰 설계 선택임
- Postgres에서 장시간 실행 작업을 돌리는 건 전혀 새로운 일이 아님. 예로 pg_cron이 있음
-
인기 있는 프로그래밍 언어나 가상 머신이 이미 결정성, 계량 가능하고 제어 가능한 단계별 실행, 런타임 상태 일시 중지, 직렬화·역직렬화와 재개를 지원했다면 필요 없었을 또 하나의 https://en.wikipedia.org/wiki/Inner-platform_effect처럼 느껴짐