trigger-realtime

Par triggerdotdev · skills

Abonnez-vous en temps réel aux exécutions de tâches Trigger.dev depuis le frontend ou le backend. À utiliser pour créer des indicateurs de progression, des tableaux de bord en direct, des réponses IA/LLM en streaming, ou des composants React affichant le statut des tâches.

npx skills add https://github.com/triggerdotdev/skills --skill trigger-realtime

Trigger.dev Realtime

Abonnez-vous aux exécutions de tâches et diffusez des données en temps réel depuis le frontend et le backend.

Quand l'utiliser

  • Construire des indicateurs de progression pour les tâches longues
  • Créer des tableaux de bord en direct montrant l'état des tâches
  • Diffuser les réponses IA/LLM vers l'interface utilisateur
  • Composants React qui déclenchent et surveillent les tâches
  • Attendre l'approbation de l'utilisateur dans les tâches

Authentification

Créer un token d'accès public (Backend)

import { auth } from "@trigger.dev/sdk";

// Token en lecture seule pour des exécutions spécifiques
const publicToken = await auth.createPublicToken({
  scopes: {
    read: {
      runs: ["run_123"],
      tasks: ["my-task"],
    },
  },
  expirationTime: "1h",
});

// Passez ce token à votre frontend

Créer un Trigger Token (pour le déclenchement depuis le frontend)

const triggerToken = await auth.createTriggerPublicToken("my-task", {
  expirationTime: "30m",
});

Abonnements Backend

import { runs, tasks } from "@trigger.dev/sdk";

// Déclencher et s'abonner
const handle = await tasks.trigger("my-task", { data: "value" });

for await (const run of runs.subscribeToRun(handle.id)) {
  console.log(`Status: ${run.status}`);
  console.log(`Progress: ${run.metadata?.progress}`);

  if (run.status === "COMPLETED") {
    console.log("Output:", run.output);
    break;
  }
}

// S'abonner aux exécutions étiquetées
for await (const run of runs.subscribeToRunsWithTag("user-123")) {
  console.log(`Run ${run.id}: ${run.status}`);
}

// S'abonner à un lot
for await (const run of runs.subscribeToBatch(batchId)) {
  console.log(`Batch run ${run.id}: ${run.status}`);
}

React Hooks

Installation

npm add @trigger.dev/react-hooks

Déclencher une tâche depuis React

"use client";
import { useRealtimeTaskTrigger } from "@trigger.dev/react-hooks";
import type { myTask } from "../trigger/tasks";

function TaskTrigger({ accessToken }: { accessToken: string }) {
  const { submit, run, isLoading } = useRealtimeTaskTrigger<typeof myTask>(
    "my-task",
    { accessToken }
  );

  return (
    <div>
      <button 
        onClick={() => submit({ data: "value" })} 
        disabled={isLoading}
      >
        Start Task
      </button>

      {run && (
        <div>
          <p>Status: {run.status}</p>
          <p>Progress: {run.metadata?.progress}%</p>
          {run.output && <p>Result: {JSON.stringify(run.output)}</p>}
        </div>
      )}
    </div>
  );
}

S'abonner à une exécution existante

"use client";
import { useRealtimeRun } from "@trigger.dev/react-hooks";
import type { myTask } from "../trigger/tasks";

function RunStatus({ runId, accessToken }: { runId: string; accessToken: string }) {
  const { run, error } = useRealtimeRun<typeof myTask>(runId, {
    accessToken,
    onComplete: (run) => {
      console.log("Completed:", run.output);
    },
  });

  if (error) return <div>Error: {error.message}</div>;
  if (!run) return <div>Loading...</div>;

  return (
    <div>
      <p>Status: {run.status}</p>
      <p>Progress: {run.metadata?.progress || 0}%</p>
    </div>
  );
}

S'abonner aux exécutions étiquetées

"use client";
import { useRealtimeRunsWithTag } from "@trigger.dev/react-hooks";

function UserTasks({ userId, accessToken }: { userId: string; accessToken: string }) {
  const { runs } = useRealtimeRunsWithTag(`user-${userId}`, { accessToken });

  return (
    <ul>
      {runs.map((run) => (
        <li key={run.id}>{run.id}: {run.status}</li>
      ))}
    </ul>
  );
}

Streams en temps réel (IA/LLM)

Définir un Stream (emplacement partagé)

// trigger/streams.ts
import { streams } from "@trigger.dev/sdk";

export const aiStream = streams.define<string>({
  id: "ai-output",
});

Canaliser le Stream dans la tâche

import { task } from "@trigger.dev/sdk";
import { aiStream } from "./streams";

export const streamingTask = task({
  id: "streaming-task",
  run: async (payload: { prompt: string }) => {
    const completion = await openai.chat.completions.create({
      model: "gpt-4",
      messages: [{ role: "user", content: payload.prompt }],
      stream: true,
    });

    const { waitUntilComplete } = aiStream.pipe(completion);
    await waitUntilComplete();
  },
});

Lire le Stream dans React

"use client";
import { useRealtimeStream } from "@trigger.dev/react-hooks";
import { aiStream } from "../trigger/streams";

function AIResponse({ runId, accessToken }: { runId: string; accessToken: string }) {
  const { parts, error } = useRealtimeStream(aiStream, runId, {
    accessToken,
    throttleInMs: 50,
  });

  if (error) return <div>Error: {error.message}</div>;
  if (!parts) return <div>Waiting for response...</div>;

  return <div>{parts.join("")}</div>;
}

Wait Tokens (Humain dans la boucle)

Dans la tâche

import { task, wait } from "@trigger.dev/sdk";

export const approvalTask = task({
  id: "approval-task",
  run: async (payload) => {
    // Traiter les données initiales
    const processed = await processData(payload);

    // Attendre l'approbation humaine
    const approval = await wait.forToken<{ approved: boolean }>({
      token: `approval-${payload.id}`,
      timeoutInSeconds: 86400, // 24 heures
    });

    if (approval.approved) {
      return await finalizeData(processed);
    }

    throw new Error("Not approved");
  },
});

Compléter le Token depuis React

"use client";
import { useWaitToken } from "@trigger.dev/react-hooks";

function ApprovalButton({ tokenId, accessToken }: { tokenId: string; accessToken: string }) {
  const { complete } = useWaitToken(tokenId, { accessToken });

  return (
    <div>
      <button onClick={() => complete({ approved: true })}>
        Approve
      </button>
      <button onClick={() => complete({ approved: false })}>
        Reject
      </button>
    </div>
  );
}

Propriétés de l'objet Run

Propriété Description
id Identifiant unique de l'exécution
status QUEUED, EXECUTING, COMPLETED, FAILED, CANCELED
payload Entrée de la tâche (typée)
output Résultat de la tâche (typé, une fois complétée)
metadata Données mises à jour en temps réel
createdAt Horodatage de démarrage
costInCents Coût d'exécution

Bonnes pratiques

  1. Limiter les tokens — n'accordez que les permissions nécessaires
  2. Définir des délais d'expiration — n'utilisez pas de tokens de longue durée
  3. Utiliser des hooks typés — passez les types de tâche pour une inférence correcte
  4. Gérer les erreurs — vérifiez toujours les erreurs dans les hooks
  5. Limiter la fréquence des streams — utilisez throttleInMs pour contrôler les re-rendus

Consultez references/realtime.md pour la documentation complète.

Skills similaires