DBOS TypeScript: Postgres 기반 경량의 내구성 있는 워크플로우
요약
DBOS는 Postgres 데이터베이스를 기반으로 경량의 내구성 있는 워크플로우 기능을 제공하는 오픈 소스 라이브러리입니다. 별도의 오케스트레이터나 태스크 큐 시스템 없이, 코드 주석 처리만으로 프로그램에 안정적인 워크플로우와 큐를 추가할 수 있습니다. 이는 서버 충돌 시에도 거래 처리를 보장하거나, 중단된 장기 데이터 파이프라인을 체크포인트에서 재개해야 할 때 유용합니다.
핵심 포인트
- Postgres 기반으로 경량의 내구성 있는 워크플로우 제공
- 별도의 오케스트레이터나 큐 시스템 관리 불필요
- 코드 주석 처리만으로 안정적인 상태 저장 및 복구 가능
- 결제 서비스, 장기 데이터 파이프라인 등 실패 처리가 중요한 경우 적합
DBOS Transact: 경량의 내구성 있는 워크플로우 (Lightweight Durable Workflows)
문서화 (Documentation) • 예제 (Examples) • GitHub • Discord
</div>DBOS란 무엇인가?
DBOS는 Postgres를 기반으로 경량의 내구성 있는 워크플로우(durable workflows)를 제공합니다. 자체적인 워크플로우 오케스트레이터(workflow orchestrator)나 태스크 큐 시스템(task queue system)을 관리할 필요 없이, DBOS를 사용하면 단 몇 줄의 코드로 프로그램에 내구성 있는 워크플로우와 큐를 추가할 수 있습니다.
시작하려면 빠른 시작 (quickstart)을 따라 이 오픈 소스 라이브러리를 설치하고 Postgres 데이터베이스에 연결하세요. 그런 다음, 프로그램 내의 워크플로우와 단계를 주석 처리(annotate)하여 내구성 있게 만드세요! 이것이 전부입니다. DBOS는 전적으로 이 오픈 소스 라이브러리 안에 포함되어 있어, 추가로 구성하거나 관리해야 할 인프라가 없습니다.
언제 DBOS를 사용해야 하는가?
애플리케이션이 실패를 안정적으로 처리해야 한다면 DBOS 사용을 고려해야 합니다. 예를 들어, 서버가 작업 도중에 충돌하더라도 거래(transactions)를 안정적으로 처리해야 하는 결제 서비스나, 중단되었을 때 처음부터 다시 시작하는 대신 체크포인트에서 원활하게 재개되어야 하는 장기 실행 데이터 파이프라인(long-running data pipeline)을 구축하고 있을 수 있습니다.
실패를 처리하는 것은 비용이 많이 들고 복잡하며, 복잡한 상태 관리 및 복구 로직뿐만 아니라 외부 오케스트레이션 서비스와 같은 무거운 도구가 필요합니다.
DBOS는 이를 더 간단하게 만듭니다: 코드를 주석 처리하여 Postgres에 체크포인트하고 모든 실패로부터 자동으로 복구할 수 있습니다.
또한 DBOS는 내구성 있는 큐(durable queues), 알림(notifications), 스케줄링(scheduling), 이벤트 처리(event processing), 프로그램적 워크플로우 관리(programmatic workflow management)를 포함하여 안정적인 코드를 작성하고 운영하기 쉽게 만드는 강력한 Postgres 기반 기본 요소들을 제공합니다.
기능 (Features)
<details open><summary><strong>💾 내구성 있는 워크플로우 (Durable Workflows)</strong></summary>DBOS 워크플로우는 상태를 Postgres에 체크포인트하여 프로그램의 **내구성(durable)**을 확보합니다.
프로그램이 실패하더라도 다시 시작할 때 모든 워크플로우가 마지막으로 완료된 단계부터 자동으로 재개됩니다.
일반 함수를 워크플로우 및 단계로 등록하여 기존 TypeScript 프로그램에 내구성 있는 워크플로우를 추가할 수 있습니다:
async function stepOne() {
DBOS.logger.info('Step one completed!');
}
...
워크플로우는 특히 다음 경우에 유용합니다:
- 비즈니스 프로세스를 오케스트레이션하여 어떤 실패로부터도 원활하게 복구되도록 할 때.
- 관찰 가능하고 장애 허용적인 데이터 파이프라인을 구축할 때.
- 신뢰성이 없거나 비결정론적(non-deterministic) API에 의존하는 AI 에이전트 또는 모든 애플리케이션을 운영할 때.
DBOS 큐는 백그라운드에서 작업을 내구성 있게(durably) 실행하는 데 도움을 줍니다.
내구성 있는 워크플로우에서 워크플로우를 큐에 넣을 수 있으며, 프로세스 중 하나가 이를 가져와 실행합니다.
DBOS는 작업의 실행을 관리합니다: 애플리케이션이 중단되더라도 작업이 완료됨을 보장하고, 호출자가 작업을 재제출할 필요 없이 결과를 얻도록 보장합니다.
큐(Queues)는 또한 흐름 제어(flow control) 기능을 제공하므로, 큐별 또는 프로세스별로 작업의 동시성(concurrency)을 제한할 수 있습니다.
또한 작업에 대한 시간 초과(timeouts)를 설정하거나, 대기 중인 작업이 실행되는 빈도를 속도 제한(rate limit)할 수 있고, 작업을 중복 제거(deduplicate)하거나 우선순위(prioritize)를 지정할 수도 있습니다.
워크플로우에 큐를 단 몇 줄의 코드로 추가할 수 있습니다. 별도의 큐잉 서비스나 메시지 브로커가 필요하지 않고, Postgres만 있으면 됩니다.
import { DBOS } from '@dbos-inc/dbos-sdk';
const queueName = 'example_queue';
...
워크플로우는 Postgres 테이블의 행(rows)으로 저장되므로, 이를 완전히 프로그램적으로 제어할 수 있습니다. 워크플로우 실행을 쿼리하거나, 일괄적으로 일시 중지 또는 재개하거나, 심지어 특정 단계에서 실패한 워크플로우를 다시 시작하는 스크립트를 작성하세요. 수천 개의 워크플로우에 영향을 미치는 버그나 장애를 강력하고 유연하게 처리할 수 있습니다.
// Postgres 데이터베이스에 연결된 DBOS 클라이언트 생성
const client = await DBOSClient.create({ systemDatabaseUrl: process.env.DBOS_SYSTEM_DATABASE_URL! });
...
DBOS를 사용하여 이벤트를 수신할 때 워크플로우를 '정확히 한 번(exactly-once)' 시작함으로써, 신뢰성 있는 웹훅(webhooks), 이벤트 리스너(event listeners), 또는 Kafka 컨슈머(Kafka consumers)를 구축하세요. 이벤트를 즉시 승인(acknowledge)하는 동시에 백그라운드에서 안정적으로 처리할 수 있습니다.
예를 들어:
async function handleMessage(request: Request): Promise<void> {
const eventId = request.body['event_id'];
// 이벤트 ID를 비지정성 키(idempotency key)로 사용하여 워크플로우를 정확히 한 번 시작...
...
크론(cron) 구문을 사용하여 워크플로우를 예약하거나, durable sleep을 사용하여 원하는 시간(심지어 며칠 또는 몇 주) 동안 워크플로우를 일시 중지한 후 실행할 수 있습니다.
몇 줄의 코드로 워크플로우를 예약할 수 있습니다:
async function scheduledFunction(schedTime: Date, context: unknown) {
DBOS.logger.info(`I am a workflow scheduled to run every 30 seconds`);
}
...
단 한 줄의 코드로 모든 워크플로우에 durable sleep을 추가할 수 있습니다.
이것은 깨어날 시간을 Postgres에 저장하므로, 워크플로우가 어떤 중단이나 재시작에도 불구하고 잠들어 있다가 항상 예정대로 다시 시작됩니다.
async function reminderWorkflowFunction(email: string, timeToSleep: number): Promise<void> {
await DBOS.runStep(() => sendConfirmationEmail(email));
await DBOS.sleep(timeToSleep);
...
알림을 받을 때까지 워크플로우 실행을 일시 중지하거나, 워크플로우에서 이벤트를 발생시켜 외부 클라이언트에게 진행 상황 업데이트를 보낼 수 있습니다.
모든 알림은 Postgres에 저장되므로, 정확히 한 번만(exactly-once semantics) 전송 및 수신될 수 있습니다.
이벤트 대기 시 지속적인 타임아웃을 설정하여, 중단이나 재시작에도 불구하고 원하는 시간(심지어 며칠 또는 몇 주) 동안 기다릴 수 있으며, 알림이 도착하거나 타임아웃에 도달하면 다시 시작됩니다.
예를 들어, 결제 서비스로부터의 알림을 지속적으로 기다리며 정확히 한 번만 처리하는 신뢰할 수 있는 청구 워크플로우를 구축할 수 있습니다:
async function billingWorkflowFunction(): Promise<void> {
// ... 요금을 계산한 후, 결제 서비스에 청구를 제출합니다.
const paymentStatus = await DBOS.recv<string>(PAYMENT_STATUS, paymentServiceTimeout);
...
시작하기 (Getting Started)
시작하려면 quickstart를 따라 이 오픈 소스 라이브러리를 설치하고 Postgres 데이터베이스에 연결하세요.
그런 다음, programming guide를 확인하여 내구성 있는 워크플로우와 큐를 구축하는 방법을 알아보세요.
문서 (Documentation)
예제 (Examples)
[https://docs.dbos.dev/examples]
DBOS 대 다른 시스템 (DBOS vs. Other Systems)
<details><summary><strong>DBOS 대 Temporal</strong></summary>DBOS와 Temporal 모두 내구성 있는 실행(durable execution)을 제공하지만, DBOS는 경량의 Postgres 기반 라이브러리로 구현된 반면 Temporal은 외부에서 오케스트레이션되는 서버로 구현됩니다.
DBOS를 프로그램에 추가하려면 이 오픈 소스 라이브러리를 설치하고, Postgres에 연결하며, 워크플로우와 스텝을 주석 처리(annotating)하면 됩니다.
반면에 Temporal을 프로그램에 추가하려면, 워크플로우와 스텝(activity)을 Temporal worker로 옮기도록 프로그램을 재설계(rearchitect)해야 하고, 해당 워크플로우를 오케스트레이션할 Temporal 서버를 구성하며, Temporal 클라이언트를 통해서만 워크플로우에 접근해야 합니다.
이 블로그 게시물에서 더 자세한 비교를 할 수 있습니다.
DBOS 사용 시점: 최소한의 재설계로 애플리케이션에 내구성 있는 워크플로우를 추가해야 하거나, Postgres를 사용하고 있을 때.
Temporal 사용 시점: 스택에 Postgres를 추가하고 싶지 않거나, DBOS가 아직 지원하지 않는 언어가 필요할 때.
</details> <details><summary><strong>DBOS 대 Airflow</strong></summary> ####DBOS와 Airflow 모두 워크플로우 추상화를 제공합니다. Airflow는 데이터 과학 사용 사례를 목표로 하며 많은 기본 연결자(out-of-the-box connectors)를 제공하지만, 워크플로우를 명시적인 DAG(Directed Acyclic Graph)로 작성하고 Airflow 클러스터에서 외부적으로 오케스트레이션해야 합니다.
Airflow는 배치 작업에 설계되었으며 스트리밍 또는 실시간 사용 사례에는 적합한 성능을 제공하지 않습니다. DBOS는 범용적이지만 데이터 파이프라인에 자주 사용되며, 개발자가 코드로 워크플로우를 작성할 수 있게 하고 Postgres 외의 인프라가 필요 없습니다.
DBOS를 사용해야 할 때: 워크플로우를 코드로 작성하는 유연성이 필요하거나 Airflow가 제공할 수 있는 것보다 높은 성능이 필요한 경우(특히 스트리밍 또는 실시간 사용 사례).
Airflow를 사용해야 할 때: Airflow의 연결자 생태계가 필요한 경우.
<details><summary><strong>DBOS vs. BullMQ</strong></summary>DBOS는 BullMQ와 같은 전용 메시지 큐잉 시스템과 유사한 큐 추상화를 제공합니다. 즉, 큐를 선언하고, 작업(task)을 제출하며, 동시성 제한(concurrency limits), 속도 제한(rate limits), 타임아웃, 우선순위 지정 등으로 흐름을 제어할 수 있습니다.
하지만 DBOS의 큐는 내구성이 있으며 Postgres 기반이고 내구성 있는 워크플로우와 통합됩니다. 예를 들어, DBOS에서는 천 개의 작업을 예약하고 그 결과를 기다리는 내구성 있는 워크플로우를 작성할 수 있습니다. DBOS는 워크플로우와 각 작업(task)을 Postgres에 체크포인트하여, 실패나 중단이 발생하더라도 작업이 완료되고 워크플로우가 그 결과를 수집하도록 보장합니다.
반면 BullMQ는 Redis 기반이며 워크플로우를 제공하지 않기 때문에 보장은 덜하지만 성능은 더 좋습니다.
DBOS를 사용해야 할 때: 내구성 있는 워크플로우에서 작업을 예약하는 신뢰성이 필요한 경우.
BullMQ를 사용해야 할 때: 내구성은 필요 없고, Postgres 서버가 지원할 수 있는 것 이상의 매우 높은 처리량(throughput)이 필요하거나, 작업을 수동으로 가져와야 하는 경우(DBOS 큐는 푸시 기반입니다).
</details>커뮤니티
질문하거나 커뮤니티와 교류하고 싶다면, Discord에서 저희와 함께하세요!
버그를 발견했거나 기능 요청 사항이 있다면, 주저하지 말고 GitHub에 이슈를 열어주세요.
기여하는 것에 관심이 있다면, contributions guide를 확인해 주세요.
AI 자동 생성 콘텐츠
본 콘텐츠는 HN AI Engineering의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기