Фабрика подключений

Фабрика подключений к STOMP-клиенту представляет собой слой абстракции, отвечающий за создание, конфигурацию и управление жизненным циклом экземпляров клиента STOMP.js. В условиях веб-приложений, где требуется работа с WebSocket-соединениями, такой подход позволяет централизовать параметры подключения, унифицировать поведение клиента и упростить масштабирование логики взаимодействия с брокером сообщений.

STOMP.js предоставляет низкоуровневый API для работы с протоколом STOMP поверх WebSocket. В базовом сценарии разработчик напрямую создаёт экземпляр клиента и настраивает его:

  • адрес брокера
  • заголовки подключения
  • обработчики событий
  • параметры переподключения
  • транспорт WebSocket

При росте приложения такой подход приводит к дублированию конфигурации и расхождению поведения клиентов в разных частях системы. Фабрика подключений решает эту проблему, вводя единый механизм создания клиента.

Ключевая идея заключается в том, что создание STOMP-клиента становится функцией или модулем, который инкапсулирует:

  • стандартные настройки подключения
  • стратегию создания WebSocket
  • политику повторного подключения
  • добавление заголовков аутентификации
  • регистрацию обработчиков событий жизненного цикла

Базовая структура фабрики

Фабрика подключений чаще всего реализуется как функция, возвращающая настроенный экземпляр Client из STOMP.js:

import { Client } from '@stomp/stompjs';

export function createStompClient(options = {}) {
  const client = new Client({
    brokerURL: options.brokerURL,
    reconnectDelay: options.reconnectDelay ?? 5000,
    heartbeatIncoming: options.heartbeatIncoming ?? 10000,
    heartbeatOutgoing: options.heartbeatOutgoing ?? 10000,
  });

  return client;
}

На этом уровне фабрика уже решает задачу централизации параметров. Однако в реальных приложениях такой вариант является лишь отправной точкой.

Инкапсуляция WebSocket-инициализации

Одним из ключевых аспектов STOMP.js является возможность переопределения способа создания WebSocket через webSocketFactory. Это особенно важно в случаях, когда требуется:

  • добавление токена авторизации в URL
  • использование нестандартного транспорта
  • подключение через прокси
  • динамическое формирование адреса

Фабрика подключений может полностью управлять этим процессом:

import { Client } from '@stomp/stompjs';

export function createStompClient({ token, baseUrl }) {
  return new Client({
    webSocketFactory: () => {
      const url = `${baseUrl}?token=${encodeURIComponent(token)}`;
      return new WebSocket(url);
    },
    reconnectDelay: 5000,
  });
}

В этом варианте фабрика перестаёт быть просто генератором конфигурации и становится точкой управления транспортным уровнем.

Централизация аутентификации

В современных веб-приложениях WebSocket-соединение почти всегда требует аутентификации. STOMP.js не навязывает способ передачи токенов, поэтому разработчик должен самостоятельно определить стратегию.

Фабрика подключений позволяет унифицировать добавление заголовков:

export function createStompClient({ getToken }) {
  const client = new Client({
    brokerURL: 'wss://example.com/ws',
    connectHeaders: {
      Authorization: `Bearer ${getToken()}`,
    },
    beforeConnect: () => {
      client.connectHeaders.Authorization = `Bearer ${getToken()}`;
    },
  });

  return client;
}

Использование beforeConnect позволяет динамически обновлять токен перед каждой попыткой подключения, что критично при работе с истекающими сессиями.

Управление жизненным циклом клиента

Фабрика может не только создавать клиента, но и контролировать его поведение после создания. В STOMP.js жизненный цикл включает этапы:

  • создание клиента
  • подключение
  • подписка на топики
  • обработка сообщений
  • отключение
  • переподключение

Фабрика может встроить стандартные обработчики событий:

export function createStompClient() {
  const client = new Client({
    brokerURL: 'wss://example.com/ws',
    reconnectDelay: 5000,
  });

  client.onConn ect = (frame) => {
    console.log('Connected:', frame.headers);
  };

  client.onStompEr ror = (frame) => {
    console.error('Broker error:', frame.headers['message']);
  };

  client.onWebSocketCl ose = () => {
    console.log('WebSocket closed');
  };

  return client;
}

Такой подход позволяет стандартизировать реакцию приложения на ключевые события без необходимости повторной настройки в каждом модуле.

Поддержка нескольких окружений

Фабрика подключений часто используется для различения окружений:

  • локальная разработка
  • тестовый сервер
  • продакшн

Вместо разрозненной логики выбора URL в разных частях приложения, вся логика концентрируется внутри фабрики:

export function createStompClient() {
  const env = process.env.NODE_ENV;

  const brokerURL =
    env === 'production'
      ? 'wss://prod.example.com/ws'
      : 'ws://localhost:8080/ws';

  return new Client({
    brokerURL,
    reconnectDelay: 3000,
  });
}

Такой подход уменьшает вероятность ошибок конфигурации при деплое.

Параметризуемая фабрика

Более гибкий вариант предполагает, что фабрика принимает конфигурационный объект, но при этом применяет дефолтные значения и правила валидации:

export function createStompClient(config) {
  const defaults = {
    reconnectDelay: 5000,
    heartbeatIncoming: 10000,
    heartbeatOutgoing: 10000,
  };

  const finalConfig = {
    ...defaults,
    ...config,
  };

  const client = new Client(finalConfig);

  return client;
}

Такой подход обеспечивает баланс между гибкостью и контролем. Приложение получает возможность переопределять параметры, но базовые настройки остаются неизменными.

Фабрика как единая точка интеграции middleware-логики

В сложных приложениях STOMP-клиент становится частью инфраструктуры, где требуется:

  • логирование сообщений
  • метрики соединений
  • трассировка запросов
  • обработка ошибок
  • синхронизация состояния

Фабрика позволяет встроить эти механизмы на этапе создания клиента:

export function createStompClient({ logger }) {
  const client = new Client({
    brokerURL: 'wss://example.com/ws',
  });

  client.onConn ect = () => {
    logger.info('STOMP connected');
  };

  client.onStompEr ror = (frame) => {
    logger.error('STOMP error', frame.body);
  };

  client.onWebSocketCl ose = () => {
    logger.warn('WebSocket closed');
  };

  return client;
}

Таким образом, клиент перестаёт быть изолированным объектом и становится частью наблюдаемой системы.

Повторное использование и изоляция состояния

Одним из ключевых преимуществ фабрики является контроль над тем, создаётся ли новый экземпляр клиента или используется существующий. Это влияет на:

  • количество открытых WebSocket-соединений
  • стабильность подписок
  • потребление ресурсов
  • поведение при навигации SPA

Фабрика может реализовывать как создание нового клиента, так и кэширование:

let instance = null;

export function getStompClient() {
  if (instance) {
    return instance;
  }

  instance = new Client({
    brokerURL: 'wss://example.com/ws',
    reconnectDelay: 5000,
  });

  return instance;
}

Хотя это уже приближается к паттерну singleton, фабрика остаётся более гибким механизмом, так как может комбинировать оба подхода в зависимости от параметров.

Динамическая реконфигурация клиента

В некоторых сценариях требуется пересоздание клиента при изменении параметров среды: смена пользователя, обновление токена, переключение контекста.

Фабрика позволяет реализовать такой сценарий явно:

let client = null;

export function resetStompClient(config) {
  if (client) {
    client.deactivate();
  }

  client = new Client(config);
  return client;
}

Это обеспечивает контролируемое завершение старого соединения перед созданием нового, предотвращая утечки подписок и дублирование сообщений.

Разделение ответственности

Фабрика подключений отделяет:

  • конфигурацию транспорта
  • управление соединением
  • бизнес-логику подписок
  • обработку сообщений

Такое разделение соответствует принципу единой ответственности. STOMP-клиент остаётся инфраструктурным объектом, а фабрика становится точкой сборки.

В результате код приложения получает предсказуемую структуру:

  • единый источник конфигурации
  • единый механизм создания клиента
  • стандартизированное поведение соединений
  • изоляцию изменений транспортного слоя

Расширяемость фабрики

Фабрика подключений может быть расширена дополнительными слоями:

  • retry-стратегии с экспоненциальной задержкой
  • адаптеры для разных брокеров (RabbitMQ, ActiveMQ, Apollo)
  • интеграция с state manager (Redux, Pinia, Vuex)
  • автоматическая регистрация подписок

Такая архитектура превращает фабрику в инфраструктурный компонент, который управляет не только созданием клиента, но и всей логикой взаимодействия с брокером сообщений на уровне приложения.