Retour à l'accueil

Intégration Next.js avec 1C Bitrix : Transfert de leads asynchrone

Guide pratique d'intégration asynchrone de Next.js 16 avec 1C Bitrix. Utilisation de after() pour le traitement des leads en arrière-plan, mise en place des mécanismes de retry et schéma PostgreSQL. Résolution des problèmes de timeout et de doublons.

Next.js et 1C Bitrix : comment envoyer des leads sans files d'attente et workers
Advertisement 728x90

Transfert asynchrone de prospects de Next.js vers 1C-Bitrix : Un pattern sans file d'attente ni worker

La soumission synchrone de prospects au CRM via l'API REST provoque des problèmes critiques : l'utilisateur attend une réponse jusqu'à ce que la requête externe se termine, et l'instabilité de l'API 1C-Bitrix entraîne des timeouts et des erreurs. Nous proposons une solution sur Next.js 16 qui élimine les files d'attente et les processus en arrière-plan. L'implémentation enregistre le prospect dans une base de données PostgreSQL locale, répond instantanément à l'utilisateur et gère l'intégration avec Bitrix via after() — un mécanisme de traitement en arrière-plan après l'envoi de la réponse HTTP.

Architecture sans file d'attente : Trois couches de responsabilité

Principe clé — séparer les opérations en parties synchrones et asynchrones. Lors de la réception du formulaire :

  • Validation des données via zod
  • Enregistrement en PostgreSQL avec bitrix_id=NULL
  • Réponse immédiate 200 OK
  • Envoi en arrière-plan vers Bitrix via after()

Cela garantit :

Google AdInline article slot
  • L'indépendance de la stabilité de l'API REST Bitrix
  • Pas de blocage de l'interface utilisateur
  • Possibilité de traiter manuellement les prospects non livrés via SELECT * FROM leads WHERE bitrix_id IS NULL

La caractéristique clé de cette approche est l'abandon de Redis/BullMQ. Toutes les opérations s'intègrent dans une route API Next.js, en utilisant after() intégré pour le traitement post-réponse. Cela réduit la complexité de l'infrastructure et simplifie le déploiement sur VPS via systemd/nginx.

after() dans Next.js 16 : Implémentation technique

La méthode after() résout le problème du « fire-and-forget » dans les environnements serverless. Contrairement à Promise.resolve().then(), elle garantit l'exécution de la tâche même après l'envoi de la réponse, sans terminer le processus avant l'achèvement de l'opération. Exemple de traitement de formulaire :

export async function POST(request: Request) {
  // ... validatsiya and antidubl
  
  const [lead] = await pgQuery(...);

  after(async () => {
    try {
      const bitrixId = await sendToBitrix24(payload);
      await pgQuery(
        `UPDATE leads SET bitrix_id = $1 WHERE id = $2`,
        [bitrixId, lead.id]
      );
    } catch (error) {
      console.error("[Leads API] Error otpravki in Bitriks:", error);
    }
  });

  return Response.json({ ok: true, id: lead.id });
}

Nuances clés :

Google AdInline article slot
  • Anti-duplication implémentée via une fenêtre de 10 minutes en PostgreSQL, pas via Bitrix (le CRM accepte les doublons sans avertissement)
  • bitrix_id stocké comme text nullable — reflète la nature asynchrone de l'opération
  • Les erreurs d'intégration sont journalisées dans journalctl, sans affecter la réponse utilisateur

Client HTTP fiable pour 1C-Bitrix

Paramètres critiques pour un travail stable avec une API instable :

  • MAX_ATTEMPTS = 2 — équilibre entre fiabilité et charge
  • REQUEST_TIMEOUT_MS = 8000 — au-dessus de la latence p95 de Bitrix (400-700 ms)
  • RETRY_DELAY_MS = 1500 — backoff linéaire sans complexité exponentielle

L'implémentation du client inclut :

async function bitrixRequest(method: string, payload: Record<string, unknown>) {
  for (let attempt = 1; attempt <= MAX_ATTEMPTS; attempt++) {
    const controller = new AbortController();
    const timer = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);

    try {
      const response = await fetch(url, {
        signal: controller.signal,
        // ...
      });

      const text = await response.text();
      const json = text ? JSON.parse(text) : {};

      if (!response.ok || json.error) {
        throw new Error(json.error_description || `HTTP ${response.status}`);
      }

      return json;
    } catch (error) {
      if (attempt >= MAX_ATTEMPTS) throw error;
      await new Promise(r => setTimeout(r, RETRY_DELAY_MS));
    } finally {
      clearTimeout(timer);
    }
  }
}

Trois points clés :

Google AdInline article slot
  • Parsing manuel via response.text() au lieu de response.json() — contourne les erreurs Bitrix avec réponses vides
  • Gestion de deux types d'erreurs : statuts HTTP et erreurs internes du CRM
  • Nettoyage garanti du timer dans finally — prévient les fuites mémoire

Fonctionnalités d'authentification et schéma de données

Pour l'intégration, webhook entrant choisi plutôt qu'OAuth :

  • Pas de dépendance au Marketplace et aux approbations
  • Gestion simple de la variable d'environnement BITRIX_WEBHOOK_URL
  • Scopes configurés dans le panneau d'administration Bitrix

Risque de fuite de token dans l'URL minimisé par la règle : les logs et le code n'affichent que la méthode API, pas l'URL complète.

Schéma de la table leads :

CREATE TABLE leads (
  id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
  name text NOT NULL,
  phone text NOT NULL,
  source text,
  bitrix_id text,
  created_at timestamptz NOT NULL DEFAULT now()
);

Pourquoi bitrix_id text, pas integer ?

  • Bitrix retourne l'ID comme string en JSON
  • Pas besoin de conversion de type
  • UUID en PostgreSQL assure l'idempotence

Points clés

  • Source unique de vérité — DB locale : prospect enregistré avant contact avec Bitrix, assurant les données même en cas d'échec du CRM
  • Traitement post-réponse : after() remplace les files d'attente, éliminant la complexité infrastructurelle
  • Gestion des erreurs : tentatives avec timeouts et journalisation journalctl assurent l'observabilité
  • Anti-duplication au niveau DB : fenêtre de 10 minutes par téléphone prévient les doublons indépendamment du CRM
  • Authentification sécurisée : webhook nécessite un contrôle strict des logs d'URL

Ce pattern convient aux projets avec jusqu'à 50 requêtes par minute. Pour les systèmes à forte charge, ajoutez une surveillance via SELECT COUNT(*) FROM leads WHERE bitrix_id IS NULL et des tentatives automatiques via cron. Dans l'implémentation actuelle, la gestion manuelle des erreurs est préférable aux tentatives automatiques — cela réduit le risque de duplication de prospects lors de pannes temporaires.

— Editorial Team

Advertisement 728x90

Lire ensuite