Powrót do strony głównej

Integracja Next.js z 1C-Bitrix: asynchroniczne przekazywanie leadów

Praktyczny przewodnik po asynchronicznej integracji Next.js 16 z 1C-Bitrix. Użycie after() do przetwarzania leadów w tle, konfiguracja mechanizmów retry i schematu PostgreSQL. Rozwiązanie problemów z timeoutami i duplikatami.

Next.js i 1C-Bitrix: jak wysyłać leady bez kolejek i workerów
Advertisement 728x90

# Asynchroniczne przekazywanie leadów z Next.js do 1C Bitrix: wzorzec bez kolejek i workerów

Synchroniczne wysyłanie leadów do CRM przez REST API powoduje krytyczne problemy: użytkownik czeka na odpowiedź do czasu zakończenia zewnętrznego zapytania, a niestabilność API 1C Bitrix wywołuje timeouty i błędy. Proponujemy rozwiązanie oparte na Next.js 16, które eliminuje kolejki i procesy w tle. Implementacja zapisuje leada w lokalnej bazie PostgreSQL, natychmiast odpowiada użytkownikowi, a integrację z Bitriksem realizuje za pomocą after() — mechanizmu przetwarzania w tle po wysłaniu odpowiedzi HTTP.

Architektura bez kolejek: trzy warstwy odpowiedzialności

Kluczowa zasada — podział operacji na część synchroniczną i asynchroniczną. Po otrzymaniu formularza:

  • Walidacja danych za pomocą zod
  • Zapis do PostgreSQL z bitrix_id=NULL
  • Natychmiastowa odpowiedź 200 OK
  • Asynchroniczne wysłanie do Bitrikxa za pomocą after()

To gwarantuje:

Google AdInline article slot
  • Niezależność od stabilności REST API Bitrikxa
  • Brak blokady interfejsu użytkownika
  • Możliwość ręcznej obróbki niesprawionych leadów za pomocą SELECT * FROM leads WHERE bitrix_id IS NULL

Cechą tego podejścia jest rezygnacja z Redis/BullMQ. Wszystkie operacje mieszczą się w API route Next.js, wykorzystując wbudowany after() do przetwarzania po wysłaniu odpowiedzi. To zmniejsza złożoność infrastruktury i ułatwia wdrożenie na VPS za pomocą systemd/nginx.

after() w Next.js 16: techniczna implementacja

Metoda after() rozwiązuje problem „ogień-i-zapomnij” w środowiskach serverless. W przeciwieństwie do Promise.resolve().then(), gwarantuje wykonanie zadania nawet po wysłaniu odpowiedzi, nie kończąc procesu przed zakończeniem operacji. Przykład obróbki formularza:

export async function POST(request: Request) {
  // ... waliacja i antyduplikat
  
  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 });
}

Ważne niuanse:

Google AdInline article slot
  • Antyduplikat zaimplementowany za pomocą okna 10 minut w PostgreSQL, a nie przez Bitrikx (CRM akceptuje duplikaty bez ostrzeżenia)
  • bitrix_id przechowywane jako nullable text — odzwierciedla asynchroniczny charakter operacji
  • Błędy integracji logowane w journalctl, bez wpływu na odpowiedź użytkownika

Niezawodny klient HTTP dla 1C Bitrix

Krytyczne parametry dla stabilnej pracy z niestabilnym API:

  • MAX_ATTEMPTS = 2 — równowaga między niezawodnością a obciążeniem
  • REQUEST_TIMEOUT_MS = 8000 — powyżej p95 latencji Bitrikxa (400-700 ms)
  • RETRY_DELAY_MS = 1500 — liniowy backoff bez wykładniczej złożoności

Implementacja klienta obejmuje:

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);
    }
  }
}

Trzy kluczowe aspekty:

Google AdInline article slot
  • Ręczny parsowanie przez response.text() zamiast response.json() — omija błędy Bitrikxa z pustymi odpowiedziami
  • Obsługa dwóch typów błędów: statusy HTTP i wewnętrzne błędy CRM
  • Gwarantowane czyszczenie timera w finally — zapobiega wyciekom pamięci

Cechy autentykacji i schematu danych

Do integracji wybrano incoming webhook zamiast OAuth:

  • Brak zależności od Marketplace i aprobat
  • Proste zarządzanie zmienną środowiskową BITRIX_WEBHOOK_URL
  • Scope'y konfiguruje się w panelu admin Bitrikxa

Ryzyko wycieku tokena w URL minimalizowane przez zasadę: w logach i kodzie podaje się tylko metodę API, a nie pełny URL.

Schemat tabeli 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()
);

Dlaczego bitrix_id jako text, a nie integer?

  • Bitrix zwraca ID jako string w JSON
  • Brak potrzeby konwersji typów
  • UUID w PostgreSQL zapewnia idempotentność

Co jest ważne

  • Źródło prawdy — lokalna baza danych: lead jest zapisywany przed obrascheniem do Bitrikxa, co gwarantuje dane nawet przy awarii CRM
  • Przetwarzanie po wysłaniu odpowiedzi: after() zastępuje kolejki, eliminując złożoność infrastruktury
  • Zarządzanie błędami: retry z timeoutami i logowanie w journalctl zapewniają obserwowalność
  • Antyduplikat na poziomie bazy danych: okno 10 minut po numerze telefonu zapobiega duplikatom niezależnie od CRM
  • Bezpieczna autentykacja: webhook wymaga ścisłej kontroli logowania URL

Ten wzorzec nadaje się do projektów o obciążeniu do 50 zapytań na minutę. W systemach o wysokim obciążeniu zaleca się dodać monitoring za pomocą SELECT COUNT(*) FROM leads WHERE bitrix_id IS NULL oraz automatyczne retry za pomocą cron. W obecnej implementacji ręczna obróbka błędów jest preferowana przed automatycznymi ponownymi próbami — zmniejsza ryzyko duplikacji leadów przy tymczasowych awariach.

— Editorial Team

Advertisement 728x90

Czytaj dalej