File d'attente

La queue livre une charge utile (payload) à un handler de votre application. Elle est at-least-once et fire-and-forget : elle ne stocke aucun résultat et n'expose aucun statut par message. Vous mettez un message en file, puis la plateforme appelle le handler HTTP enregistré pour cette queue.

Mettre en file

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

const sdk = createSdk("<app-id>");
const id = await sdk.queue.push("emails", { to: "a@b.com" });

Appelez-la côté serveur (loader, action, route.ts ou tâche). push(queue, payload, delaySecs?) retourne l'identifiant du message et lève une erreur si la plateforme refuse la mise en file. Une charge utile qui n'est pas une chaîne est sérialisée avec JSON.stringify ; une chaîne est envoyée telle quelle.

Note

Le troisième argument, delaySecs, retarde la livraison : le message n'est remis qu'après ce délai, en secondes entières (une valeur non entière est ignorée et le message part tout de suite). Pour un traitement récurrent, utilisez plutôt une planification.

Enregistrer un handler

Chaque queue est traitée par un handler : une URL HTTP de votre application que la plateforme appelle pour chaque message. Le client du framework n'a pas d'appel pour en enregistrer un : les handlers HTTP sont activés pour votre application par la plateforme, avec les réglages suivants :

Réglage Obligatoire Rôle
queue oui Nom de la queue à traiter
handler_url oui URL du handler, par exemple https://<app>.inklura.fr/api/queue/emails
concurrency non Nombre maximal de livraisons simultanées (1 par défaut, 1 au minimum)
visibility_timeout_secs non Durée qu'une livraison peut prendre avant d'être retentée (30 par défaut)

Le handler_url doit être une URL http ou https sur le domaine de votre application (un nom de domaine, sans identifiants ni fragment #), parmi les URL de rappel que la plateforme a autorisées pour elle. La plateforme attend la réponse de votre handler jusqu'à visibility_timeout_secs, avec un minimum de 30 secondes et un maximum de 15 minutes : 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 retentée.

Contrat du handler

La plateforme envoie ce corps en POST à votre handler_url :

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

attempts compte les livraisons précédentes : 0 à la première. Toute livraison compte, y compris celles qui finissent en délai dépassé.

Avec sdk.queue.push, payload arrive sous forme de chaîne JSON (la charge utile est sérialisée avant l'envoi) : décodez-la avec JSON.parse, comme dans l'exemple plus bas.

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

Réponse Effet
2xx ack : le message est traité
408, 429, 5xx retry : relivré après le délai Retry-After que vous envoyez (nombre entier de secondes, au moins 1), 30 secondes par défaut, plafonné à visibility_timeout_secs
tout autre statut dead-letter : le message part dans la queue morte
pas de réponse (injoignable, délai dépassé) retry une fois visibility_timeout_secs écoulé

Un message part en dead-letter après 5 tentatives de livraison. Un Retry-After sous forme de date HTTP n'est pas pris en compte : le délai par défaut s'applique.

Écrivez le handler sous forme de route.ts :

export async function POST(request: Request) {
  const { id, payload, attempts } = await request.json();
  const data = typeof payload === "string" ? JSON.parse(payload) : payload;
  try {
    await sendEmail(data);
    return new Response(null, { status: 200 }); // ack
  } catch (e) {
    return new Response(String(e), { status: 500 }); // retry
  }
}

Sémantique à prévoir

  • At-least-once : un handler peut recevoir le même message plusieurs fois. Rendez vos handlers idempotents, par exemple en dédupliquant sur id.
  • Fire-and-forget : la mise en file retourne un id, rien de plus. Il n'existe pas de moyen intégré de savoir si le message X a réussi.
  • Dead-letter : les messages qui épuisent leurs tentatives, ou dont le handler renvoie un statut non réessayable, arrivent dans la queue morte. Ils y restent avec leur charge utile et peuvent être listés, remis en file (tous ou un par un, avec un compteur de tentatives remis à zéro) ou purgés.
  • Entrée non fiable : le handler est une route de votre application comme une autre. Traitez le corps reçu comme une entrée externe et, avant une action irréversible, revérifiez l'état que vous avez stocké plutôt que de vous fier à la seule charge utile.

Ajouter un enregistrement de job pour suivre un statut

Comme la queue ne stocke pas de résultat, une application qui a besoin de l'issue conserve un enregistrement de job durable en KV : des clés comme job:<id> que le handler met à jour (queued → running → complete / fail).

Queue ou tasks

Pour un traitement long avec statut et progression intégrés, utilisez plutôt les Tasks. La queue convient à une livraison en volume, sans retour, vers un handler HTTP.

Et ensuite

Page Ce qu'elle couvre
Tasks & Planificateur Traitements longs avec statut et progression, planification
KV Store Le motif d'enregistrement de job durable
Queue Workers Exploiter et observer les handlers