Powrót do strony głównej

SSE powiadomienia w SPA: czas rzeczywisty bez polling

Artykuł opisuje architekturę asynchronicznych powiadomień w SPA na bazie SSE i Mercure. Integracja z CDC do śledzenia zmian w bazie danych, ponowne wykorzystanie schematów OpenAPI do typizacji. Przykłady kodu i schematy dla programistów.

Push-powiadomienia SSE w SPA: architektura i kod
Advertisement 728x90

Asynchroniczne aktualizacje danych w SPA za pomocą SSE i Mercure

Aplikacje frontendowe wymagają ciągłego odświeżania danych, aby odzwierciedlać zmiany zachodzące po stronie backendu. Standardowe zapytania API przechwytują stan w momencie odpowiedzi, ale backend nadal przetwarza zdarzenia: doładowania kont, moderację treści, odpowiedzi działu wsparcia. Aby rozwiązać ten problem, stosuje się mechanizmy push oparte na SSE, zintegrowane z istniejącą specyfikacją OpenAPI.

System łączy podejście pull (okresowe zapytania) z push (powiadomieniami w czasie rzeczywistym). SSE zapewnia jednokierunkowy strumień zdarzeń przez HTTP/2, minimalizując obciążenie w porównaniu z pollingiem.

Scenariusze zastosowania asynchronicznych powiadomień

Asynchroniczne powiadomienia są kluczowe w procesach biznesowych:

Google AdInline article slot
  • Doładowanie salda: wyświetlanie aktualnego stanu dla natychmiastowego zakupu.
  • Moderacja treści: aktualizacja statusu po weryfikacji.
  • Odpowiedzi wsparcia: natychmiastowe powiadomienie o nowym zgłoszeniu.

W typowym przypadku użytkownik — reklamodawca lub wykonawca — śledzi liczniki zgłoszeń: liczbę wymagających działania, nieprzeczytanych komentarzy, weryfikacji publikacji. Te dane są dostępne przez endpoint API /rest/User/info (operationId: getInfo).

/rest/User/info:
  get:
    tags:
      - User
    summary: Zwraca informacje o aktualnym użytkowniku
    operationId: getInfo
    responses:
      200:
        description: Informacje o aktualnym użytkowniku
        content:
          application/json:
            schema:
              type: object
              properties:
                id:
                  type: integer
                  format: int32
                  minimum: 0
                locale:
                  type: string
                  enum: [ru, en]
                login:
                  type: string
                  minimum: 3
                  maximum: 320
                seoCounters:
                  $ref: '#/components/schemas/SeoCounters'

Schemat SeoCounters definiuje strukturę:

SeoCounters:
  type: object
  properties:
    nofRequests:
      type: integer
      format: int32
      minimum: 0
    nofLinksStatusNeedApprove:
      type: integer
      format: int32
      minimum: 0
    nofLinksWithUnreadComments:
      type: integer
      format: int32
      minimum: 0
    nofChanges:
      type: integer
      format: int32
      minimum: 0
    nofPlacementCheck:
      type: integer
      format: int32
      minimum: 0

Integracja CDC i Data Platform

Zmiany w tabeli user_counters są śledzone przez CDC (Change Data Capture). Strumień modyfikacji jest przekazywany do Data Platform — korporacyjnego systemu ETL. Stamtąd zdarzenia są wypychane do UI przez hub SSE.

Google AdInline article slot

Architektura wykorzystuje model heksagonalny: specyfikacja OpenAPI automatycznie generuje adaptery REST i typy TypeScript. Dla frontendu typy wyglądają tak:

/* Generated by orval */
export interface SeoCounters {
  nofRequests?: number;
  nofLinksStatusNeedApprove?: number;
  nofLinksWithUnreadComments?: number;
  nofChanges?: number;
  nofPlacementCheck?: number;
}

export type GetInfo200 = {
  id: number;
  locale: 'ru' | 'en';
  login: string;
  seoCounters?: SeoCounters;
};

Te typy są ponownie wykorzystywane do obsługi zdarzeń SSE, zapewniając bezpieczeństwo typów.

Implementacja SSE w aplikacji

SSE (Server-Sent Events) — standard dla pushy serwerowych, obsługiwany przez przeglądarki. EventSource łączy się z endpointem:

Google AdInline article slot
const evtSource = new EventSource('/sse-endpoint', {
  withCredentials: true,
});

evtSource.onmessage = (event) => {
  const data = JSON.parse(event.data);
  // Aktualizacja stanu z danymi typowanymi
  updateSeoCounters(data.seoCounters);
};

Do autoryzacji, tematów i skalowania stosuje się Mercure — open-source hub oparty na SSE. Hub przyjmuje publikacje przez REST z JWT i rozsyła subskrybentom.

Przykład publikacji:

curl -d 'topic=https://example.com/books/1' \
     -d 'data={"foo": "updated value"}' \
     -H 'Authorization: Bearer <JWT>' \
     -X POST https://hub/.well-known/mercure

JWT definiuje uprawnienia do publikacji/subskrypcji według tematów. Mercure jest wdrażany jako kontener z zewnętrzną bazą danych, integruje się ze strumieniami CDC.

Zalety podejścia

  • Ponowne wykorzystanie schematów: Struktury OpenAPI są używane w pull i push bez duplikacji.
  • Czas rzeczywisty: Zmiany są odzwierciedlane natychmiast bez polling.
  • Skalowalność: Hub Mercure rozkłada obciążenie.

Lista kluczowych liczników do monitorowania:

  • nofRequests — zgłoszenia do działania.
  • nofLinksStatusNeedApprove — linki do zatwierdzenia.
  • nofLinksWithUnreadComments — nieprzeczytane komentarze.
  • nofPlacementCheck — weryfikacje publikacji.

Co jest ważne

  • SSE z Mercure zapewnia typowane powiadomienia push bez nakładki WebSocket.
  • CDC przechwytuje zmiany w bazie danych w czasie rzeczywistym dla procesów ETL.
  • Autogeneracja typów TypeScript z OpenAPI gwarantuje spójność danych.
  • Podejście skaluje się dla systemów high-load z tysiącami użytkowników.
  • JWT w Mercure zarządza dostępem do tematów powiadomień.

— Editorial Team

Advertisement 728x90

Czytaj dalej