Workers de file

La queue du SDK livre chaque message au moins une fois. Vous ajoutez des messages dans une file (voir SDK → Queue) et un worker les traite : un handler HTTP de votre application que la plateforme appelle en POST pour chaque message. Chaque application ne voit que ses propres files et ses propres workers.

Réglages d'un worker

Un worker est défini pour une file par les réglages suivants. Le client du framework n'a pas d'appel pour enregistrer un worker : les workers HTTP sont activés pour votre application par la plateforme.

Champ Requis Notes
queue oui Nom de la file à traiter
handler_url oui L'URL du handler, sur le domaine de votre application
concurrency non Nombre maximal de livraisons simultanées (1 par défaut, 1 au minimum)
visibility_timeout_secs non Durée accordée à une livraison avant qu'elle soit relancée (30 par défaut)

Une file n'a qu'un worker : en définir un nouveau remplace le précédent. Les workers peuvent aussi être listés et retirés.

Un message part en lettre morte après 5 livraisons sans acquittement.

Note

handler_url doit être une URL http ou https avec un nom de domaine (pas d'adresse IP, pas d'identifiants ni de fragment #), située sous l'une des URL de rappel que la plateforme a autorisées pour votre application. Une URL mal formée est refusée avec 400 ; si les workers HTTP ne sont pas activés pour l'application, ou si l'URL n'est pas autorisée, le refus est un 403. Si l'autorisation est retirée plus tard, les livraisons sont suspendues sans consommer de tentative.

Exemple de réglages :

{
  "queue": "emails",
  "handler_url": "https://<app>.inklura.fr/api/queue/emails",
  "concurrency": 4,
  "visibility_timeout_secs": 60
}

Le contrat du handler

À chaque livraison, la plateforme envoie cette enveloppe JSON en POST à votre handler_url :

{ "id": "<message-id>", "queue": "emails", "payload": { }, "attempts": 0 }

payload porte la valeur passée à push. Avec sdk.queue.push, elle arrive sous forme de chaîne JSON : décodez-la avec JSON.parse, comme dans l'exemple plus bas. attempts compte les livraisons précédentes : 0 à la première. Les messages d'une file sont pris dans leur ordre d'arrivée, mais avec une concurrency supérieure à 1 plusieurs livraisons se déroulent en parallèle.

Le statut HTTP de votre réponse décide de la suite :

Statut de réponse Suite
2xx Acquitté : le message est terminé et supprimé
408, 429, 5xx Relance : le message est relivré plus tard (jusqu'à 5 livraisons)
tout autre statut Lettre morte : le message part dans la file de lettres mortes, sans relance
pas de réponse (injoignable, délai dépassé) Relance une fois visibility_timeout_secs écoulé

Sur un statut de relance, un en-tête Retry-After (un nombre entier de secondes) fixe le délai avant la nouvelle livraison ; sans lui, le délai est de 30 secondes. Dans les deux cas, il est plafonné au délai de visibilité. Votre handler dispose de visibility_timeout_secs pour répondre (30 secondes au minimum, 900 au maximum) : réglez-le au-dessus de la durée d'exécution la plus longue de votre handler, sinon une livraison lente mais réussie est relancée.

// src/app/api/queue/emails/route.ts
export async function POST(req: Request) {
  const { id, payload, attempts } = await req.json();
  const data = typeof payload === "string" ? JSON.parse(payload) : payload;
  try {
    await sendEmail(data);
    return new Response("ok");                 // 2xx → acquitté
  } catch (e) {
    if (isTransient(e)) {
      return new Response("retry", {           // 5xx → relance dans 60 s
        status: 503,
        headers: { "Retry-After": "60" },
      });
    }
    return new Response("bad payload", { status: 400 }); // 4xx → lettre morte
  }
}
Attention

La livraison est au moins une fois. Un même message peut arriver plusieurs fois (par exemple si votre réponse 2xx s'est perdue, ou après un délai de visibilité dépassé). Rendez vos handlers idempotents en vous appuyant sur l'id du message.

Suivre un job : ajoutez un enregistrement en KV

La queue ne stocke aucun résultat. Une fois un message acquitté, il disparaît : rien ne permet de savoir ensuite si le job a réussi ni ce qu'il a produit. Si vous avez besoin d'un statut ou d'un résultat, écrivez votre propre enregistrement, idéalement dans le KV sous une clé job:<id>.

import { createSdk } from "@bext-stack/framework/sdk";

const sdk = createSdk("<app-id>");

// à l'ajout dans la file (push renvoie l'id du message)
const id = await sdk.queue.push("emails", payload);
await sdk.kv.set(`job:${id}`, { status: "queued", createdAt: Date.now() });

// dans le handler, id vient de l'enveloppe
await sdk.kv.set(`job:${id}`, { status: "running" });
// …travail…
await sdk.kv.set(`job:${id}`, { status: "done", result });

kv.set remplace toute la valeur : reprenez les champs que vous voulez garder à chaque écriture.

Si vous avez besoin d'un statut et d'une progression intégrés, utilisez plutôt les tasks.

Lettres mortes

Les messages qui épuisent leurs 5 livraisons, ou pour lesquels le handler a renvoyé un statut non relançable, arrivent dans la file de lettres mortes. Ils y restent, avec leur charge utile, jusqu'à ce que vous les relanciez ou les purgiez :

Opération Rôle
Lister Consulter les messages en lettre morte (50 par défaut, 500 au plus) avec leur charge utile et leur nombre de tentatives
Relancer Remettre les messages dans la file, compteur de tentatives remis à zéro (toute une file, ou un message par son id)
Purger Supprimer définitivement les messages (toute une file, ou un message par son id)

Voir aussi