Класс BackgroundSyncQueue

BackgroundSyncQueue — это один из ключевых инструментов библиотеки Workbox, предназначенный для обеспечения надежной доставки запросов, когда клиент временно находится в оффлайне. Класс реализует очередь запросов, которые будут автоматически повторно отправлены, когда устройство восстановит соединение с сетью.

Основные возможности

  • Автоматическая повторная отправка: запросы, добавленные в очередь, будут пытаться отправиться снова, когда сеть станет доступной.
  • Гибкая конфигурация стратегии повторов: можно задать максимальное количество попыток, интервал повторной отправки и поведение при сбоях.
  • Интеграция с сервис-воркерами: BackgroundSyncQueue работает на уровне сервис-воркера, обеспечивая сохранность данных даже при закрытии браузера или перезагрузке страницы.
  • Поддержка различных типов запросов: можно помещать в очередь любые fetch-запросы — POST, PUT, DELETE и даже GET-запросы с важными параметрами.

Создание и настройка очереди

Создание очереди происходит через конструктор BackgroundSyncQueue. Основной синтаксис:

import { BackgroundSyncQueue } from 'workbox-background-sync';

const myQueue = new BackgroundSyncQueue('myQueueName', {
  maxRetentionTime: 24 * 60, // Время хранения запросов в минутах
  onSync: async ({ queue }) => {
    let entry;
    while ((entry = await queue.shiftRequest())) {
      try {
        await fetch(entry.request);
      } catch (error) {
        await queue.unshiftRequest(entry);
        throw error;
      }
    }
  }
});

Параметры конструктора:

  • queueName — уникальное имя очереди. Оно используется для идентификации сохраненных запросов в IndexedDB.
  • options.maxRetentionTime — время жизни запроса в очереди в минутах. После истечения этого времени запрос удаляется автоматически.
  • options.onSync — асинхронная функция, вызываемая при срабатывании синхронизации. В ней происходит обработка всех сохраненных запросов.

Добавление запросов в очередь

Запросы можно помещать в очередь напрямую через метод pushRequest:

const request = new Request('/api/data', {
  method: 'POST',
  body: JSON.stringify({ key: 'value' }),
  headers: { 'Content-Type': 'application/json' }
});

await myQueue.pushRequest({ request });

Ключевые моменты при работе с pushRequest:

  • Объект запроса должен быть полноценным экземпляром Request.
  • Все заголовки и тело запроса сохраняются в очереди и будут восстановлены при повторной отправке.
  • Метод возвращает промис, который резолвится, когда запрос успешно добавлен в очередь IndexedDB.

Обработка синхронизации

Workbox позволяет автоматизировать повторную отправку запросов через событие sync сервис-воркера:

self.addEventListener('sync', (event) => {
  if (event.tag === 'myQueueName') {
    event.waitUntil(myQueue.replayRequests());
  }
});
  • event.tag должен совпадать с именем очереди, переданным при создании.
  • Метод replayRequests() последовательно отправляет все запросы из очереди.
  • Если какой-либо запрос не удается отправить, он возвращается обратно в начало очереди для последующих попыток.

Интеграция с Workbox Routing

Очередь можно связать с конкретными маршрутами через registerRoute из Workbox Routing. Например, для всех POST-запросов на /api/data:

import { registerRoute } from 'workbox-routing';
import { NetworkOnly } from 'workbox-strategies';

registerRoute(
  ({ url, request }) => url.pathname.startsWith('/api/data') && request.method === 'POST',
  new NetworkOnly({
    plugins: [myQueue]
  }),
  'POST'
);
  • Используется стратегия NetworkOnly, чтобы запросы сначала пытались отправиться в сеть.
  • В случае сетевой ошибки BackgroundSyncQueue автоматически сохраняет их для последующей отправки.

Управление очередью

BackgroundSyncQueue предоставляет несколько методов для работы с очередью:

  • replayRequests() — вручную инициирует повторную отправку всех запросов.
  • pushRequest({ request }) — добавляет новый запрос.
  • shiftRequest() — извлекает первый запрос из очереди для обработки.
  • unshiftRequest(entry) — возвращает неудачный запрос обратно в очередь.
  • getAll() — возвращает массив всех текущих запросов в очереди.
  • deleteQueue() — очищает все запросы из очереди.

Особенности и подводные камни

  • Хранение в IndexedDB: все запросы сохраняются в IndexedDB, что может вызвать проблемы с большими объёмами данных или сложными объектами, например, FormData.
  • Синхронизация при закрытом браузере: поддерживается только в браузерах, которые реализуют Background Sync API. Если браузер не поддерживает этот API, запросы не будут повторно отправлены автоматически.
  • Ограничение по размеру очереди: хотя явного ограничения нет, чрезмерное количество запросов может замедлить обработку.
  • Идempotентность запросов: важно, чтобы повторная отправка не нарушала логику сервера. Не стоит помещать в очередь запросы, которые могут вызвать нежелательные побочные эффекты при повторной отправке.

Практические рекомендации

  • Разделять очереди по типам данных, например, отдельная очередь для логирования и отдельная для пользовательских изменений.
  • Использовать обработку ошибок в onSync для повторной постановки запроса в очередь.
  • Настраивать maxRetentionTime, исходя из предполагаемого времени нахождения пользователя оффлайн.
  • При необходимости сохранять дополнительную информацию о состоянии запроса (например, ID пользователя) в теле или заголовках запроса для корректной обработки на сервере.

BackgroundSyncQueue обеспечивает надежную доставку данных при нестабильном соединении и является мощным инструментом для Progressive Web Apps, где важна гарантированная синхронизация с сервером.