Les applications d’IA modernes ne sont plus de simples appels d’inférence ; ce sont des agents de longue durée qui planifient, agissent, observent et réessaient au fil du temps. Une boucle d’agent IA qui récupère du contexte depuis un vector store, appelle un LLM, écrit des résultats en base de données, attend une validation humaine, puis déclenche des actions en aval peut s’exécuter pendant des minutes, des heures, voire des jours. Sans une couche d’orchestration durable, toute défaillance d’infrastructure transitoire relance l’intégralité de la boucle depuis le début : refacturant des appels LLM coûteux, dupliquant les effets de bord et perdant tout le contexte accumulé.
La plupart des plateformes d’orchestration de workflows résolvent ce problème en déployant un cluster dédié à côté de votre application. DBOS adopte une approche fondamentalement différente : il intègre l’exécution durable directement dans votre application via la base de données que vous utilisez déjà. Votre base de données n’est pas seulement un store de données : c’est le moteur d’exécution. Associez DBOS à CockroachDB et vous obtenez une plateforme d’exécution distribuée globalement et auto-réparante, sans infrastructure supplémentaire à gérer.
Un workflow durable est une fonction dont l’état d’exécution, à savoir quelles étapes ont été complétées, ce qu’elles ont retourné et quelles entrées ont été fournies, est persisté en base après chaque étape. Si le processus crashe en cours d’exécution, il redémarre et reprend depuis la dernière étape validée : aucun travail n’est perdu, aucune étape n’est ré-exécutée, aucun effet de bord externe n’est dupliqué.
Qu’est-ce que DBOS ?
DBOS est une bibliothèque Python et TypeScript qui décore des fonctions ordinaires avec des garanties d’exécution durable. Il n’y a pas de serveur à déployer, pas de file de tâches à opérer, pas de cluster de persistance séparé à gérer. DBOS écrit l’état des workflows dans des tables de votre base applicative comme effet secondaire de l’exécution normale, et récupère depuis ces tables au redémarrage.
Concepts clés
| Concept | Définition |
|---|---|
@DBOS.workflow() |
Décorateur rendant une fonction Python durable. L’état est persisté avant chaque étape. |
@DBOS.step() |
Unité de travail dans un workflow ; s’exécute au moins une fois mais jamais après complétion |
| Workflow ID | La clé d’idempotence ; lancer deux fois le même ID de workflow est sans danger |
DBOS.set_event() |
Publie une valeur nommée depuis l’intérieur d’un workflow pour les consommateurs externes |
DBOS.get_event() |
Interroge un workflow pour une valeur d’événement nommée avec timeout optionnel |
| Base système | La base compatible PostgreSQL où DBOS stocke l’état des workflows, les completions d’étapes et les événements |
Architecture
DBOS gère trois catégories de tables dans la base système :

Schéma de la base système DBOS : l’état des workflows vit dans votre base, pas dans un service séparé
- Table de statut des workflows : une ligne par exécution, suivant l’ID, le statut et les entrées de la fonction
- Table des sorties d’opérations : une ligne par étape complétée, stockant la valeur de retour sérialisée pour la reprise
- Table d’événements : paires clé-valeur nommées publiées dans les workflows et consommées via
get_event
Quand un processus crashe et redémarre, DBOS rejoue la fonction de workflow contre les sorties d’étapes sauvegardées. Toute étape dont le résultat est déjà en base est ignorée instantanément. Seules les étapes incomplètes sont ré-exécutées. Le résultat est une sémantique d’exécution exactement-une-fois sans service d’orchestration dédié.
Pourquoi CockroachDB pour DBOS ?
DBOS utilisant le protocole filaire PostgreSQL, il se connecte à CockroachDB directement sans modification de driver. Ce que CockroachDB ajoute par rapport à un PostgreSQL mono-nœud, c’est le niveau de persistance que vous avez toujours voulu mais que vous ne pouviez pas justifier d’opérer séparément :
- Isolation sérialisable : les exécutions de workflow concurrentes ne produisent jamais de mises à jour perdues ni de lectures fantômes
- Réplication active-active multi-région : l’état des workflows est durable à travers les défaillances de data center sans intervention manuelle
- Scalabilité horizontale : la base système passe à l’échelle avec votre application sans re-sharding
- Basculement automatique : les défaillances de nœuds CockroachDB sont transparentes pour DBOS, qui réessaie simplement sur le nœud suivant disponible
Pour les équipes souhaitant des workflows agentiques résilients globalement sans la complexité d’un cluster Temporal, DBOS + CockroachDB est le chemin à moindre overhead.
Déployer DBOS sur CockroachDB
Deux modifications de configuration sont nécessaires lors de l’utilisation de CockroachDB à la place de PostgreSQL.
1. Désactiver LISTEN/NOTIFY
Le mécanisme LISTEN/NOTIFY de PostgreSQL est utilisé par DBOS pour réveiller les workflows en attente sans polling. CockroachDB n’implémente pas ce mécanisme et il doit être désactivé explicitement. DBOS bascule automatiquement sur le polling :
from dbos import DBOS, DBOSConfig
from sqlalchemy import create_engine
import os
database_url = os.environ["DBOS_COCKROACHDB_URL"]
engine = create_engine(database_url)
config: DBOSConfig = {
"name": "my-agent-app",
"system_database_url": database_url,
# Pass a pre-built SQLAlchemy engine so DBOS uses the CockroachDB driver
"system_database_engine": engine,
# CockroachDB does not support LISTEN/NOTIFY — use polling instead
"use_listen_notify": False,
}
DBOS(config=config)
2. Définir l’URL de la base système
Dans dbos-config.yaml, pointer la base système vers CockroachDB en utilisant le format de chaîne de connexion PostgreSQL standard :
name: my-agent-app
language: python
runtimeConfig:
start:
- python3 app/main.py
system_database_url: ${DBOS_COCKROACHDB_URL}
Définissez la variable d’environnement avec votre chaîne de connexion CockroachDB :
export DBOS_COCKROACHDB_URL="postgresql://dbos_user:password@<crdb-host>:26257/dbos_system?sslmode=verify-full&sslrootcert=/certs/ca.crt"
Un workflow agentique DBOS complet sur CockroachDB
L’exemple suivant implémente un workflow d’agent durable en trois étapes adossé à CockroachDB. Le workflow publie des événements de progression après chaque étape qu’un frontend peut interroger en temps réel. Si le processus crashe en cours d’exécution, le redémarrer reprend depuis la dernière étape complétée, sans refacturation, pas d’écriture en double, pas de perte de contexte.
import os
import time
import uvicorn
from dbos import DBOS, DBOSConfig, SetWorkflowID
from fastapi import FastAPI
from sqlalchemy import create_engine
app = FastAPI()
# ── CockroachDB connection ──────────────────────────────────────────────────
database_url = os.environ["DBOS_COCKROACHDB_URL"]
engine = create_engine(database_url)
config: DBOSConfig = {
"name": "agent-workflow",
"system_database_url": database_url,
"system_database_engine": engine,
"use_listen_notify": False, # Required: CockroachDB has no LISTEN/NOTIFY
}
DBOS(config=config)
STEPS_EVENT = "steps_event"
# ── Workflow steps ──────────────────────────────────────────────────────────
@DBOS.step()
def retrieve_context(task: str) -> str:
"""Step 1 — retrieve relevant context from the knowledge base."""
time.sleep(3)
DBOS.logger.info(f"Context retrieved for: {task}")
return f"context_for_{task}"
@DBOS.step()
def call_agent(context: str) -> str:
"""Step 2 — call the LLM/agent with the context."""
time.sleep(3)
DBOS.logger.info("Agent invocation completed")
return f"agent_response_given_{context}"
@DBOS.step()
def persist_result(response: str) -> None:
"""Step 3 — write the agent's output to the application database."""
time.sleep(3)
DBOS.logger.info(f"Result persisted: {response}")
# ── Durable workflow ────────────────────────────────────────────────────────
@DBOS.workflow()
def agent_workflow(task: str) -> None:
context = retrieve_context(task)
DBOS.set_event(STEPS_EVENT, 1)
response = call_agent(context)
DBOS.set_event(STEPS_EVENT, 2)
persist_result(response)
DBOS.set_event(STEPS_EVENT, 3)
# ── HTTP endpoints ──────────────────────────────────────────────────────────
@app.post("/agent/{task_id}")
def start_agent(task_id: str, task: str) -> dict:
"""Idempotently launch a durable agent workflow."""
with SetWorkflowID(task_id):
DBOS.start_workflow(agent_workflow, task)
return {"workflow_id": task_id, "status": "started"}
@app.get("/agent/{task_id}/progress")
def get_progress(task_id: str) -> dict:
"""Poll workflow progress (0-3 completed steps)."""
try:
step = DBOS.get_event(task_id, STEPS_EVENT, timeout_seconds=0)
except KeyError:
return {"completed_steps": 0}
return {"completed_steps": step if step is not None else 0}
if __name__ == "__main__":
DBOS.launch()
uvicorn.run(app, host="0.0.0.0", port=8000)
Installez les dépendances et lancez :
pip install "dbos[otel]==2.15.0" "fastapi[standard]"
export DBOS_COCKROACHDB_URL="postgresql://dbos_user:pass@localhost:26257/dbos_system?sslmode=disable"
python3 app/main.py
Bénéfices clés
| Capacité | DBOS + CockroachDB |
|---|---|
| Pas d’infrastructure supplémentaire | L’exécution durable s’exécute dans votre processus FastAPI / applicatif |
| Étapes exactement-une-fois | Les étapes ne sont jamais ré-exécutées après que leur sortie est validée dans CockroachDB |
| Lancements idempotents | Le même ID de workflow retourne toujours l’exécution existante |
| Durabilité globale | La réplication multi-région de CockroachDB protège l’état des workflows entre régions |
| Zéro modification de driver | Protocole filaire PostgreSQL. Pas de SDK CockroachDB spécifique requis. |
| Progression observable | set_event / get_event exposent la complétion des étapes aux frontends en temps réel |
Les deux modifications de configuration, use_listen_notify: False et une URL de connexion CockroachDB, sont tout ce qui est nécessaire pour rendre la base système DBOS distribuée globalement et tolérante aux pannes.