Aller au contenu
English

Choisir où stocker les données

Configurez les transports des données persistantes et repérez les fichiers qui restent dans le dépôt.

Un transport enregistre des données binaires versionnées sous des clés. Les stockages qui s’appuient dessus les interprètent comme des checkpoints, des artefacts ou d’autres données persistantes. Le transport détermine leur emplacement ; chaque stockage détermine leur contenu.

ObjetÉcrit viaSans transport fourni
CheckpointscreateWorkflowCheckpointStore({ transporter })Obligatoire
ArtefactscreateArtifactStore({ transporter })Obligatoire
Cache de résultatscreateTaskCacheStore({ transporter })Obligatoire
Spéculation durabledurability.transporter de speculate()Obligatoire
Journauxlogging.transporter d’un dispatch ou d’une sandbox.outpost/storage
Activité des ressourcesactivityTransport d’un dispatch ou d’une sandbox.outpost/storage
Réservations de stockagetransporter de reserveRecoveryStorage().outpost/storage
Conversations archivéescreateTransportConversations(store, { transporter })Non archivées
Archives de récupérationrecoveryTransport d’un dispatch ou d’une sandboxNon archivées

createLocalTransport({ directory }) stocke les objets dans un dossier local privé. Passez-lui le .outpost/storage du dépôt pour ranger vos stockages à côté des journaux et de l’activité qu’Outpost y écrit par défaut.

import {
  createArtifactStore,
  createLocalTransport,
  createTaskCacheStore,
  createWorkflowCheckpointStore,
} from "@elie-laloum/outpost";

const transporter = createLocalTransport({ directory: ".outpost/storage" });
const checkpoints = createWorkflowCheckpointStore({ transporter });
const artifacts = createArtifactStore({ transporter });
const cache = createTaskCacheStore({ transporter });

Créer un transport ou un stockage n’écrit aucune donnée. Lorsqu’un objet est enregistré, le transport local écrit son fichier de façon atomique et en réserve l’accès à son propriétaire.

  • .outpost/storage/
    • objects/Un fichier .object par clé, regroupé par préfixe.
      • checkpoints/Exécutions de workflow, une par runId.
      • artifacts/Octets des artefacts, adressés par empreinte.
      • task-cache/Résultats de tâches en cache.
      • logs/Journaux.
      • resources/Activité des sandboxes ouvertes.
      • reservations/Registre des réservations de stockage.
      • speculations/État de la spéculation durable.
      • conversations/Conversations archivées.
      • recovery/Transferts de récupération archivés.
    • .outpost/locks/Verrous qui sérialisent les processus d’écriture de cette machine.

Le reste du dossier .outpost est décrit dans la page Fonctionnement.

Passez le même transport aux stockages et aux options du dispatch : tous les objets d’une exécution arrivent au même endroit.

import {
  createLocalTransport,
  createWorkflowCheckpointStore,
  dispatch,
} from "@elie-laloum/outpost";
import { coder, repository, sandboxProvider } from "./outpost.config.ts";

const transporter = createLocalTransport({ directory: "/srv/outpost" });
const checkpoints = createWorkflowCheckpointStore({ transporter });

await dispatch({
  agent: coder,
  sandboxProvider,
  repository,
  brief: { text: "Update the changelog for the last release." },
  logging: { transporter },
  activityTransport: transporter,
  recoveryTransport: transporter,
});

Utilisez un dossier ou un préfixe distinct par projet, pour que les règles de rétention et d’accès s’appliquent à un seul ensemble d’objets.

Un transport distant conserve les mêmes contrats de stockage. S3 et R2 détaille la configuration ; seule la ligne transporter change.

import { S3Client } from "@aws-sdk/client-s3";
import { createWorkflowCheckpointStore } from "@elie-laloum/outpost";
import { createS3Transport } from "@elie-laloum/outpost/transports/s3";

const client = new S3Client({ region: "eu-west-1" });
const transporter = createS3Transport({
  client,
  bucket: "my-private-outpost",
  prefix: "outpost/",
});
const checkpoints = createWorkflowCheckpointStore({ transporter });

// ... exécutez vos workflows, puis :
client.destroy();

Votre application possède le client. Fermer une sandbox ou terminer un workflow ne le ferme jamais : détruisez-le une fois terminées toutes les opérations qui l’utilisent.

Pour créer un objet, utilisez ifRevision: null. Pour le remplacer ou le supprimer, indiquez la revision que vous avez lue. Si un autre processus a modifié l’objet entre-temps, l’opération lève TransportConflict sans écrire de données.

import { reportValue } from "./reporter.ts";
import { createLocalTransport, TransportConflict } from "@elie-laloum/outpost";

const transporter = createLocalTransport({ directory: ".outpost/storage" });
const bytes = (text: string) => new TextEncoder().encode(text);

const first = await transporter.write("notes/today", bytes("v1"), {
  ifRevision: null,
});
await transporter.write("notes/today", bytes("v2"), {
  ifRevision: first.revision,
});
try {
  await transporter.write("notes/today", bytes("v3"), {
    ifRevision: first.revision,
  });
} catch (error) {
  if (error instanceof TransportConflict) reportValue("stale:", error.key);
  // Example output: stale: notes/today
}

Le script affiche stale: notes/today. Les stockages appliquent la même barrière : un workflow qui a perdu la propriété de son checkpoint échoue à sa prochaine écriture au lieu d’écraser une exécution plus récente. Relisez l’objet avant de décider quoi faire.

  • Le transport local coordonne les processus d’une seule machine ; il n’assure pas de propriété distribuée sur NFS ou un autre montage partagé.
  • Une liste renvoie les objets actuels un par un, pas un instantané cohérent du préfixe.
  • Les révisions écartent les processus d’écriture périmés ; elles n’authentifient pas l’auteur d’un objet.
  • Les clés sont des segments séparés par /, faits de lettres, chiffres, ., _ et -, sans point initial, de 512 caractères au plus.

API : Transport · createLocalTransport · TransportConflict · createWorkflowCheckpointStore · createArtifactStore · createTaskCacheStore · createTransportConversations · SandboxOptions · createS3Transport.