オンラインに戻ったときにリクエストを再試行する

ウェブサーバーに対してリクエストを行う場合、エラーが発生する可能性があります。ユーザーの接続が切断されているか、リモート サーバーがダウンしている可能性があります。

このドキュメントでは主に Service Worker での GET リクエストの処理に重点を置いていますが、POSTPUTDELETE などの他のメソッドも使用する場合があります。これらのメソッドは、バックエンド API と通信してウェブアプリにデータを提供する際によく使用されます。Service Worker が存在せずこれらのリクエストが失敗した場合は、オンラインに戻ったときにユーザーが手動で再試行する必要があります。これはユーザーが必ず覚えておくべきことではありません。

これがアプリケーションに当てはまる場合、かつ Service Worker が混在している場合、ユーザーがオンラインに戻ったときに失敗したリクエストの送信を再試行するのが理想的です。この問題の解決策は、BackgroundSync API です。Service Worker は、ネットワーク リクエストの失敗を検出し、ブラウザが接続の復旧を検出したときに sync イベントを受信するよう設定できます。sync イベントは、ユーザーがそれを登録したページから移動した場合でも配信できるため、失敗したリクエストを再試行する他の方法よりも効果的です。

ワークボックスは、workbox-background-sync モジュールでこの API を抽象化し、BackgroundSync API を他のワークボックス モジュールと併用しやすくしています。また、BackgroundSync をまだサポートしていないブラウザ用のフォールバック戦略も実装されています。

基本的な使用方法

BackgroundSyncPluginworkbox-background-sync モジュールからエクスポートされ、失敗したリクエストをキューに入れておき、その後の sync イベントが発生したときに再試行するために使用できます。

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

const bgSyncPlugin = new BackgroundSyncPlugin('myQueueName', {
  maxRetentionTime: 24 * 60 // Retry for max of 24 Hours (specified in minutes)
});

registerRoute(
  /\/api\/.*\/*.json/,
  new NetworkOnly({
    plugins: [bgSyncPlugin]
  }),
  // An optional third parameter specifies the request method
  'POST'
);

ここでは、BackgroundSyncPlugin が、JSON データを取得する API ルートへの POST リクエストに一致するルートに適用されます。ユーザーがオフラインの場合、BackgroundSyncPlugin はユーザーがオンラインに戻ったときにリクエストを再試行しますが、再試行できるのは最大で 1 日間です。

高度な使用方法

workbox-background-sync には、失敗したリクエストをインスタンス化して追加できる Queue クラスも用意されています。BackgroundSyncPlugin の場合と同様に、失敗したリクエストは IndexedDB に保存され、接続が復元されたとブラウザが判断したときに試行されます。

キューの作成

キューを作成するには、キュー名を表す文字列を使用して Queue オブジェクトをインスタンス化します。

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

const queue = new Queue('myQueueName');

キュー名は、グローバル SyncManager によって提供される register() メソッドによって作成されるタグ名の一部として使用されます。これは、IndexedDB データベースで提供されるオブジェクト ストアに使用される名前でもあります。

キューにリクエストを追加する

Queue インスタンスを作成したら、その pushRequest() メソッドを使用して、失敗したリクエストを追加できます。

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

const queue = new Queue('myQueueName');

self.addEventListener('fetch', (event) => {
  // Add in your own criteria here to return early if this
  // isn't a request that should use background sync.
  if (event.request.method !== 'POST') {
    return;
  }

  const bgSyncLogic = async () => {
    try {
      const response = await fetch(event.request.clone());
      return response;
    } catch (error) {
      await queue.pushRequest({request: event.request});
      return error;
    }
  };

  event.respondWith(bgSyncLogic());
});

キューに追加されたリクエストは、Service Worker が sync イベントを受け取ると自動的に再試行します。これは、ネットワークが再び利用可能になったとブラウザが判断するためです。BackgroundSync API をサポートしていないブラウザは、Service Worker が起動するたびにリクエストを再試行します。これは、失敗したリクエストを再試行する効果的な方法ではなく、一種の代替方法です。

workbox-background-sync のテスト

バックグラウンド同期の動作のテストは難しい場合がありますが、Chrome DevTools で行うことができます。現在の最善のアプローチは次のようになります。

  1. Service Worker を登録するページを読み込みます。
  2. パソコンのネットワーク接続をオフにするか、ウェブサーバーをオフにします。Chrome DevTools のオフライン切り替えボタンは使用しないでください。[オフライン] チェックボックスはページからのリクエストにのみ影響し、Service Worker のリクエストは引き続き処理されます。
  3. workbox-background-sync でキューに入れるネットワーク リクエストを作成します。Chrome DevTools > Application > IndexedDB > workbox-background-sync > requests を調べると、キューに入れられたリクエストを確認できます。
  4. ネットワーク接続を復元するか、ウェブサーバーをオンに戻してください。
  5. Chrome DevTools > Application > Service Workers に移動して、早期 sync イベントを強制実行します。workbox-background-sync:<your queue name> のタグ名を入力します。ここで、<your queue name> は、設定したキューの名前です。
  6. [同期] ボタンをクリックします。
    Chrome の DevTools のアプリケーション パネルにあるバックグラウンド同期ユーティリティのスクリーンショット。同期イベントは、「workbox-background-sync」モジュールの「myQueueName」のキューに指定されています。
  7. 以前に失敗したネットワーク リクエストが再試行され、完了したことがわかります。その結果、リクエストが正常にリプレイされたため、IndexedDB ストアは空になります。

まとめ

workbox-background-sync を使用して失敗したネットワーク リクエストを再試行すると、アプリのユーザー エクスペリエンスと信頼性を向上させることができます。たとえば、失敗した API リクエストを再送信できるため、API に送信するデータが失われないようにすることができます。また、分析など、独自のデータのギャップを埋めるために使用することもできます。実際に、workbox-google-analytics モジュールは内部で workbox-background-sync を使用して、Google アナリティクスへのデータ送信に失敗したリクエストを再試行します。

ユースケースが何であれ、workbox-background-sync はこの種のタスクを簡素化し、デベロッパー エクスペリエンスを向上させ、ウェブ アプリケーションのユーザー エクスペリエンスと機能を向上させる機会を提供します。