이미 Postgres에 상태(state)를 유지하고 있으며, 백그라운드 작업의 신뢰성을 확보하기 위해 cron 작업, 워커(workers), 큐(queues), 상태 테이블(status tables)을 일일이 조합하는 과정을 멈추고 싶은 팀들을 위한 장기 실행 및 결함 허용(fault-tolerant) SQL 함수입니다. SQL에서 워크플로(workflow)를 정의하면, pg_durable가 각 단계를 체크포인트(checkpoint)로 기록하며, 충돌(crash), 재시작 또는 단계 실패 후에도 실행을 재개할 수 있습니다.
내구 실행(Durable execution)은 이제 업계의 표준 패턴이며, pg_durable는 추가적인 서비스 인프라 없이 Postgres 내부로 이를 가져옵니다. 이는 컴퓨팅을 데이터 근처로 가져오려는 우리의 미션 중 일부입니다.
[IMG:1]
성능을 위해 설계되고 pg_durable가 내장된 Microsoft의 새로운 PostgreSQL 클라우드 서비스인 Azure HorizonDB에서 지금 바로 pg_durable를 사용해 보세요.
- 자신이 다루는 데이터 옆에 워크플로가 존재하기를 원하는 백엔드 및 데이터 엔지니어.
- 재시작 후에도 생존해야 하며 SQL로 감사(auditable)가 가능한 런북(runbooks)을 자동화하려는 DBA 및 SRE.
- 행(row), 문서(document) 또는 배치(batch) 단위로 내구 실행이 필요한 데이터 또는 AI 파이프라인을 구축하는 팀.
pg_durable 함수는 PostgreSQL이 실행하면서 진행 상황을 체크포인트로 기록하는 SQL 단계들의 그래프(graph)입니다. 데이터베이스가 충돌하거나 재시작되거나 특정 단계가 실패하더라도, 사용자가 수동으로 상태를 재구성할 필요 없이 마지막 내구 체크포인트(durable checkpoint)부터 실행이 재개됩니다.
-
벡터 임베딩(Vector embedding) 파이프라인: 청크(chunk) 분할, 임베딩 API 호출, 그리고 pgvector로 업서트(upsert).
-
인제스트(Ingest) 파이프라인: 대규모 배치를 스테이징(stage), 중복 제거(deduplicate), 변환(transform) 및 게시(publish).
-
예약된 유지 관리(Scheduled maintenance): 블로트(bloat) 감지, 알림, 승인 대기 후 다음 작업 실행.
-
팬아웃 집계(Fan-out aggregation): 독립적인 쿼리를 병렬로 실행한 후 결과 결합.
-
외부 API 워크플로: SQL을 통한 데이터 보강(enrichment), 분류(classification) 및 웹훅(webhook) 스타일 호출.
-
pg_cron과 작업 테이블, 상태 컬럼, 재시도 카운터 및 폴링 워커(polling worker)를 사용하는 방식.
-
Airflow, Temporal, Step Functions 또는 Argo와 같이 Postgres로 콜백을 호출하는 외부 오케스트레이터(orchestrator).
-
재시도 및 부분 완료를 조정하기 위한 큐(queue), 워커(workers) 및 별도의 상태 테이블(state table) 조합.
-
plpgsql
충돌(crash)이 발생하거나 장시간 실행되는 트랜잭션(long-running transaction)으로 인해 처음부터 다시 시작해야 할 때까지 작동하는 프로시저(procedure).
-
긴 작업 중간에 재시작한다는 것은 이미 성공한 작업을 다시 실행해야 함을 의미합니다.
-
단 하나의 행(row) 실패나 하나의 API 호출 실패가 수동 정리 및 불확실한 재실행(replay)으로 이어집니다.
-
긴 트랜잭션은 락(locks)을 점유하고, WAL(Write-Ahead Logging)을 증가시키며, 대규모 스케일에서 배치 작업(batch jobs)을 취약하게 만듭니다.
-
애플리케이션 계층(app tier)에서의 병렬 작업은 부분 실패(partial-failure) 버그와 드리프트(drift)가 발생할 수 있는 지점을 더 많이 만듭니다.
-
워크플로(workflow) 로직이 SQL, 워커(workers), 큐(queues), 대시보드(dashboards) 및 상태 테이블(status tables)에 흩어지게 됩니다.
-
워크플로 정의가 SQL로 이동하며 df.start(...)로 시작됩니다.
-
재시도 상태(retry state), 진행 상황 추적(progress tracking) 및 체크포인팅(checkpointing)이 맞춤형 애플리케이션 코드 대신 Postgres 내부로 이동합니다.
-
일부 애플리케이션 계층의 워커, 큐 컨슈머(queue consumers) 또는 스케줄러 글루(scheduler glue)가 완전히 사라질 수 있습니다.
-
운영 가시성(operational visibility)은 데이터와 동일한 인증 및 백업 모델을 사용하는 df.instances와 같은 Postgres 테이블을 통해 확보됩니다.
-
작업이 이미 단일 INSERT ... SELECT 또는 하나의 일반적인 SQL 문입니다.
-
내구성이 있는 백그라운드 실행(durable background execution)보다는 밀리초 미만(sub-millisecond)의 동기식 요청 처리가 필요합니다.
-
Postgres 환경에 확장 기능(extensions)을 설치하거나 백그라운드 워커(background worker)를 실행할 수 없습니다.
-
워크플로가 주로 Postgres 외부에서 존재하며 많은 이기종 시스템(heterogeneous systems)에 걸쳐 있습니다.
-
SQL 단계, 분기(branching), 루프(loops) 또는 HTTP 호출로 깔끔하게 매핑되지 않는 임의의 애플리케이션 로직이 필요합니다.
-
~> 및 |=>와 같은 조합 가능한 연산자(composable operators)를 사용하여 SQL에서 워크플로를 정의합니다.
-
df.start()로 시작하고 인스턴스 ID(instance ID)를 반환받습니다.
-
런타임이 단계 사이의 체크포인팅(checkpointing)과 함께 각 단계를 내구성 있게 실행하도록 합니다.
-
워크플로가 실행 중이거나 완료된 후 PostgreSQL에서 상태 및 결과를 쿼리합니다.
이 모델은 의도적으로 SQL 형태를 띠고 있습니다. 만약 특정 단계에서 임의의 코드, 비-HTTP SDK, 또는 풍부한 인메모리 제어 흐름(in-memory control flow)이 필요하다면, 해당 로직을 SQL 함수로 래핑(wrap)하거나, df.http()를 위해 HTTP 엔드포인트 뒤로 노출시키거나, 시스템의 해당 부분에 범용 오케스트레이터(general-purpose orchestrator)를 사용해야 할 수도 있습니다.
Durable (내구성)— 함수 상태가 PostgreSQL에 유지됩니다. 충돌(crash), 재시작, 장애 조치(failover) 상황에서도 생존합니다.
SQL-native (SQL 네이티브)— 조합 가능한 연산자(composable operators)를 사용하여 SQL로 함수를 정의합니다.
Database-aware (데이터베이스 인식)— 스케줄링, 조건, 병렬 실행을 위한 일급 기본 요소(first-class primitives)를 제공합니다.
Zero infrastructure (인프라 제로)— PostgreSQL 확장(extension)으로 실행됩니다. Redis, Temporal 또는 외부 서비스가 필요하지 않습니다.
-- 단계별로 데이터를 처리하는 내구성 있는 함수
SELECT df.start(
'SELECT id FROM documents WHERE processed = false LIMIT 100' |=> 'batch'
...
태그된 릴리스(Tagged releases)는 GitHub 릴리스 자산(release assets)으로부터 amd64용 PostgreSQL 17 및 18용 Debian 패키지를 게시합니다. 패키지 이름은 pg-durable-postgresql-<PG major>_<pg_durable version>-1_<arch>.deb 형식입니다.
이 패키지는 확장 라이브러리(extension library), 제어 파일(control file), SQL 업그레이드 파일을 일치하는 PostgreSQL 설치 디렉토리에 설치합니다.
패키지를 설치한 후, pg_durable을 shared_preload_libraries에 추가하고, PostgreSQL을 재시작한 다음, 구성된 pg_durable 데이터베이스에 확장을 생성하십시오:
CREATE EXTENSION pg_durable;
기본 pg_durable 데이터베이스는 postgres입니다. 백그라운드 워커(background worker) 구성 및 권한 설정에 대해서는 사용자 가이드(User Guide)를 참조하십시오.
릴리스 자산에는 소스 빌드를 위한 소스 아카이브(source archives)도 포함되어 있습니다.
- PostgreSQL 17 또는 18
- Rust (nightly)
- cargo-pgrx 0.16.1
메인 브랜치(main branch)의 사전 빌드(prebuild)는 PostgreSQL 17을 설치하고, pg_durable을 빌드하며, 확장이 준비된 상태로 ~/.pgrx 아래에 로컬 클러스터(local cluster)를 준비합니다. PostgreSQL이 실행된 상태로 유지되지 않으므로, 작업을 시작할 때 실행하십시오.
# PostgreSQL 시작
./scripts/pg-start.sh
# 연결
...
준비된 사전 빌드가 없는 브랜치에서는 pg-start.sh를 실행하십시오. 첫 실행 시 확장을 빌드하고 설치합니다(몇 분 정도 소요될 수 있습니다):
./scripts/pg-start.sh
VS Code Dev Container (.devcontainer/)는 Rust, cargo-pgrx, PostgreSQL 17이 사전 설치된 환경을 제공합니다. 일반 로컬 머신의 경우, .devcontainer/onCreateCommand.sh의 단계를 따라 툴체인(toolchain)을 먼저 설치하십시오.
# 빌드, PostgreSQL 초기화 및 확장 기능(extension) 설치
# 시간이 다소 소요됩니다 - 다른 일을 하고 오셔도 좋습니다
./scripts/pg-start.sh
...
pg-start.sh
postgres 슈퍼유저(superuser)를 포함하여 새로운 로컬 데이터 디렉터리를 부트스트랩(bootstrap)하며, 현재 OS 사용자에 대한 일치하는 슈퍼유저 역할(role)도 생성하여 기본 로컬 psql 사용이 계속 작동하도록 합니다. 표준 부트스트랩 역할을 명시적으로 강제하려면 -U postgres를 사용하십시오.
# 빌드 및 테스트
./scripts/test-e2e-docker.sh --rebuild
# 선택 사항: ACR에 배포 (pg_durable이 포함된 커스텀 PG17 이미지용)
...
CREATE EXTENSION pg_durable는 PUBLIC에 어떠한 권한도 부여하지 않습니다. 확장 기능을 설치한 후, 관리자는 애플리케이션 역할(application roles)에 명시적으로 액세스 권한을 부여해야 합니다. 행 수준 보안 (Row-level security (RLS))은 각 사용자가 자신의 내구적 함수(durable function) 인스턴스 및 노드만 보고 관리할 수 있도록 보장합니다.
애플리케이션 역할에 권한 부여:
SELECT df.grant_usage('app_role');
또는, 간접 역할(indirection role)을 생성하고 애플리케이션 역할에 멤버십을 부여하십시오:
CREATE ROLE pg_durable_user NOLOGIN;
SELECT df.grant_usage('pg_durable_user');
...
개별 권한 부여, 액세스 취소 및 업그레이드된 설치본의 보안 강화(hardening)에 대한 전체 목록은 사용자 가이드(User Guide) — 권한 부여(Privilege Grants) 섹션을 참조하십시오.
참고: GRANT EXECUTE ON ALL FUNCTIONS는 권한 부여가 실행될 때 존재하는 함수에만 적용됩니다. ALTER EXTENSION pg_durable UPDATE로 pg_durable을 업그레이드한 후에는, 새로운 함수에 접근할 수 있도록 df.grant_usage('role')를 다시 실행하거나(또는 수동 권한 부여를 다시 수행) 하십시오.
핵심 사항:
- 백그라운드 워커 역할 (
pg_durable.worker_role GUC, 기본값: postgres)은 반드시 슈퍼유저(superuser)여야 합니다. 이 역할은 모든 사용자의 인스턴스를 관리하기 위해 RLS를 우회합니다.
- 사용자는
df.instances / df.nodes에 대해 SELECT + INSERT 권한을 가지며, df.cancel()을 위한 인스턴스의 컬럼 수준 UPDATE (status, updated_at) 권한을 가집니다.
- 식별 컬럼 (
submitted_by
)는 사용자에 의해 수정될 수 없습니다 — 각 사용자는 df.vars를 통해 자신만의 변수 네임스페이스를 가집니다.
owner 컬럼과 RLS (Row-Level Security, 행 수준 보안)를 사용하여 사용자별 스코핑 (per-user scoping)을 수행합니다. 슈퍼유저 (Superusers)는 RLS를 우회하지만, DSL 함수는 명시적 필터를 통해 여전히 호출한 사용자에게 스코핑됩니다. 비밀 정보를 평문으로 저장하는 것을 피하십시오.
모든 풀 리퀘스트 (Pull Requests)는 머지 (Merge) 전 다음 체크를 통과해야 합니다:
포맷 체크 (Format Check) — cargo fmt --check
Clippy 및 테스트 (Clippy & Tests) — cargo clippy, 단위 테스트 (cargo pgrx test pg17), pg_regress 테스트, 그리고 E2E (End-to-End) 테스트
CI 워크플로우는 .github/workflows/ci.yml에 정의되어 있습니다. 이는 pgrx를 사용하여 PostgreSQL을 다운로드하고 관리합니다.
pg_durable에는 두 가지 테스트 스위트 (Test Suites)가 있습니다:
- PostgreSQL의 표준 테스트 프레임워크를 사용하여 핵심 DSL 기능에 대해 수행하는 빠르고 결정론적인 (deterministic) 테스트:
테스트 SQL은 sql/에 위치하며, 예상 출력은 expected/에 있습니다. PGXS는 루트 Makefile에 구성되어 있습니다.
make test-regress # 전체 리셋 + 실행
make installcheck # 실행만 수행 (PostgreSQL이 이미 실행 중이어야 함)
- pgrx PostgreSQL을 사용한 복잡한 로컬 통합 테스트:
./scripts/test-e2e-local.sh # 특수 재시작/설정 단계를 포함한 모든 로컬 SQL E2E 테스트
./scripts/test-e2e-local.sh 04_parallel # 특정 테스트
./scripts/test-e2e-local.sh --default-build-phases # 기본 빌드 단계 그룹만 수행
자세한 내용은 tests/e2e/를 참조하십시오.
- 사용자 가이드 (User Guide) — 예제를 포함한 전체 사용 가이드
- MVP 가이드 (MVP Guide) — 구현 세부 사항 및 내부 구조
- 예제 (Examples) — 예제 컨벤션 및 스모크 체크 (smoke-check) 안내
pg_durable는 PostgreSQL 확장 프로그램 (pgrx로 빌드됨)입니다 — 모든 것은 PostgreSQL 서버 내부에서 실행되며, 외부 서비스는 없습니다. 이 확장 프로그램은 함수 그래프를 구축하기 위한 SQL DSL을 노출하며, 두 개의 하위 수준 Rust 라이브러리 위에서 이를 내구성 있게 (durably) 실행하는 백그라운드 워커 (background worker)를 등록합니다:
- duroxide — 오케스트레이션 런타임 (orchestration runtime: 결정론적 재생 (deterministic replay), 체크포인트 (checkpoints), 하위 오케스트레이션 (sub-orchestrations), 타이머 (timers))을 제공하는 내구성 있는 태스크 프레임워크 (durable task framework).
- duroxide-pg — duroxide를 위한 PostgreSQL 기반 상태 제공자 (state provider). 런타임 상태 (인스턴스 (instances), 히스토리 (history), 작업 큐 (work queues))를 확장 프로그램(extension)이 소유한 전용
duroxide.* 스키마에 영구 저장합니다.
┌────────────────────────────────────────────────────────────────────┐
│ PostgreSQL │
│ │
...
만약 상태를 PostgreSQL에 영구 저장하면서 Rust, Python 또는 Node에서 내구성 있는 함수 (durable functions)를 작성하고 싶다면, 호스트 언어에서 duroxide와 duroxide-pg를 직접 사용할 수 있습니다. pg_durable는 SQL로 작성하는 것을 선호할 때 이 두 조합 위에서 구축하게 되는 것입니다.
Preview - 이 프로젝트는 현재 프리뷰 (preview) 단계입니다.
버그 보고 및 기능 요청은 GitHub Issues를 사용해 주세요. 보안 취약점은 공개된 GitHub 이슈를 통해 보고하지 마십시오. 대신 SECURITY.md의 지침을 따르시기 바랍니다.
이 프로젝트는 Microsoft 오픈 소스 행동 강령 (Open Source Code of Conduct)을 채택했습니다. 자세한 내용은 행동 강령 FAQ를 참조하거나 질문 또는 의견이 있는 경우 [email protected]으로 문의하십시오.
Microsoft는 소프트웨어 제품 및 서비스의 보안을 엄격하게 다룹니다. 공개된 GitHub 이슈를 통해 보안 취약점을 보고하지 마십시오. 보안 보고 지침은 SECURITY.md를 참조하십시오.
pg_durable는 Microsoft로 텔레메트리 (telemetry)를 전송하지 않습니다.
이 프로젝트에는 프로젝트, 제품 또는 서비스에 대한 상표나 로고가 포함되어 있을 수 있습니다. Microsoft 상표 또는 로고의 허가된 사용은 Microsoft의 상표 및 브랜드 가이드라인 (Trademark & Brand Guidelines)을 따르며 이를 준수해야 합니다. 이 프로젝트의 수정 버전에서 Microsoft 상표 또는 로고를 사용하는 것은 혼란을 야기하거나 Microsoft의 후원을 암시해서는 안 됩니다. 제3자의 상표 또는 로고 사용은 해당 제3자의 정책을 따릅니다.
PostgreSQL License