Webの定期的なバックグラウンド同期

ドラフト コミュニティグループ報告,

この版:
https://wicg.github.io/periodic-background-sync/index.html
課題追跡:
GitHub
編集者:
(Google)
(Google)

要旨

この仕様は、ウェブアプリケーションがバックグラウンドで定期的にデータやコンテンツを同期できる方法を説明します。

この文書のステータス

この仕様は Web Platform Incubator Community Group によって公開されました。 これは W3C 標準ではなく、W3C の標準化プロセストラック上にもありません。 W3C Community Contributor License Agreement (CLA) に基づき、限定的なオプトアウトがあり、その他の条件が適用される点にご注意ください。 W3C Community and Business Groups について詳しくはこちら。

1. はじめに

この節は規範的ではありません。

Web アプリケーションはしばしば信頼性の低いネットワーク(例:携帯電話)や寿命が不確かな環境(ブラウザが終了される、またはユーザーが離脱する可能性がある)で動作します。 そのため、Web アプリがコンテンツや状態をサーバーと同期し続けることが困難になります。

この API は、コンテンツ作成とサーバーおよび Web アプリ間のコンテンツ同期の間の時間を短縮することを目的としています。これは、Web アプリが定期的に状態やデータを同期する意図を、望む最小間隔とともに登録できるようにすることで実現します。サービスワーカーのイベントを通じて、ユーザーエージェントは定期的に Web アプリにネットワークリソースをダウンロードさせ、状態を更新させます。

この API はサービスワーカーに依存しているため、この API が提供する機能は セキュアコンテキスト でのみ利用可能です。

1.1.

ブラウジングコンテキスト から最小間隔を 1 日にして定期的なバックグラウンド同期を登録する例:

async function registerPeriodicNewsCheck() {
  const registration = await navigator.serviceWorker.ready;
  try {
    await registration.periodicSync.register('fetch-news', {
      minInterval: 24 * 60 * 60 * 1000,
    });
  } catch {
    console.log('Periodic Sync could not be registered!');
  }
}

periodicsync イベント に対して サービスワーカー 内で反応する例:

self.addEventListener('periodicsync', event => {
  event.waitUntil(fetchAndCacheLatestNews());
});

上の例では、fetchAndCacheLatestNews は開発者が定義した関数で、サーバーから最新のニュース記事を取得してローカルに保存します。例えばオフラインでの利用のために Cache API を使用して保存します。

2. 概念

periodicsync イベントperiodic sync registration registration に対して発火したとき、その発動は関連する service worker registrationorigin に対して、service worker clients のうち、フレームタイプが "top-level"、"auxiliary"、または "nested" であるものが存在しない場合に、バックグラウンドで実行される と見なされます。

3. Service Worker 登録への拡張

service worker registration にはさらに以下が含まれます:

4. 構成要素

4.1. 定期同期登録

A periodic sync registration は次の要素で構成されます:

service worker registration、これは service worker registration です。

tag、これは DOMString です。

注: Periodic Background Sync は Background Sync と名前空間を共有しないため、ある origin は同じタグで両方のタイプの登録を持つことができます。

minimum interval(long long)は、定期同期が発生する最小間隔をミリ秒単位で指定するために使用されます。minimum interval はユーザーエージェントへの提案です。

注: 実際に periodicsync イベント が発火する間隔は、これと同じかそれ以上でなければなりません。

anchor time(タイムスタンプ)は、この periodicsync イベント がこの periodic sync registration に対して以前に発火した時刻、または初回登録の時刻です。

state は "pending"、"firing"、"suspended"、または "reregistered-while-firing" のいずれかで、初期値は "pending" に設定されます。

4.2. 定期同期スケジューラ

periodic sync schedulerperiodicsync イベント の発火スケジューリングを担当します。

これらのトリガーに応じて、スケジューラは将来の適切な時刻に periodicsync イベント を発火させるための遅延処理をスケジュールするか、またはそのスケジュールをキャンセルします。

スケジューラは次を維持します:

effective minimum sync interval for origin originorigin)は、minimum periodic sync interval for any origin に、その origin に対してユーザーエージェントが定義する量を加えたものです。

注: ユーザーエージェントが定義する量は、ユーザーのその origin へのエンゲージメント量に基づく可能性があります。この値は effective minimum sync interval for origin が呼ばれるたびに異なる場合があります。

スケジューラは 定期同期登録の処理 を行います。

注: ブラウザはリソース節約のために、アクティブな定期同期登録 が存在しない場合にこの処理ループを一時停止することがあります。

4.3. 定数

セクション § 5 プライバシーに関する考慮事項 および § 6 リソース使用 で推奨されているように、ユーザーエージェントは次も定義すべきです:

minimum periodic sync interval across originsminimum periodic sync interval for any origin 以上でなければなりません。未定義の場合、これらは 43200000(ミリ秒単位で 12 時間)に設定されます。

注: 頻度に対する 2 つの上限が必要です。なぜなら、各 origin ごとに minimum periodic sync interval for any origin による制限を順守しても、ブラウザが periodicsync イベント を非常に頻繁に発火してしまうことがあるからです。例えば、多くの異なる origin に対する periodic sync registrations が存在する場合などです。minimum periodic sync interval across origins はこれらのイベントが発火する頻度に対するグローバルな上限を保証します。

ユーザーエージェントは各 periodicsync イベント に許される 最大再試行回数(数値)を定義してもよいです。これを選定する際、ユーザーエージェントは 最大再試行回数 を試行するのに必要な時間が minimum periodic sync interval for any origin より桁違いに短いことを保証するべきです。未定義の場合、この数値はゼロです。

5. プライバシーに関する考慮事項

5.1. 権限

Periodic Background Sync は、PermissionState が、PermissionDescriptorname に対して "periodic-background-sync"granted の場合にのみ利用可能です。さらに、ユーザーエージェントはユーザーが Periodic Background Sync を無効にする方法を提供するべきです。 Periodic Background Sync が無効になっている場合、periodicsync events は、この権限の影響を受ける periodic sync registrations に対してディスパッチされてはなりません。(参照:§ 7.2 Respond to permission revocation

5.2. 位置情報の追跡

バックグラウンドでの periodicsync event 内での fetch リクエストは、ユーザーがページを離れた後にクライアントの IP アドレスをサーバーに明らかにする可能性があります。ユーザーエージェントは、再試行回数と periodicsync event の継続時間に上限を設けることで追跡を制限し、ウェブサイトによってユーザーの位置が追跡される時間を短くするべきです。さらに、ユーザーエージェントは、periodicsync event の頻度に上限を設けることで永続的な位置追跡を制限するべきであり、それは個々の origin および複数の origins 全体に対して行われるべきです。

5.3. 履歴の漏洩

periodicsync event 内で、バックグラウンドで 行われる fetch リクエストは、periodic sync registration を作成したネットワークとは別のネットワーク上にあるミドルボックスにクライアントのナビゲーション履歴に関する何らかの情報を明らかにする可能性があります。例えば、クライアントが https://example.com を訪問して periodicsync event を登録したとしても、実装によってはユーザーがページから離れてネットワークを切り替えた後まで発火しない場合があります。新しいネットワーク上のミドルボックスは、periodicsync event によって行われる fetch リクエストを見る可能性があります。fetch リクエストは HTTPS で行われるためリクエストの内容は漏れませんが、フェッチ先やドメインは(DNS ルックアップやリクエストの IP アドレスを通じて)漏れる可能性があります。閲覧履歴のこのような漏洩を防ぐために、ユーザーエージェントは periodicsync eventsperiodic sync registration が行われたネットワーク上でのみ発火させることを選択してもよいですが、その場合は同期を機会的に行えなくなるため使い勝手が低下する点に注意する必要があります。

6. リソース使用

この節は規範的ではありません。

ウェブサイトは、periodicsync event を処理するときにネットワークからリソースをダウンロードすることが多くあります。基盤となるオペレーティングシステムは、これらのイベントをディスパッチするためにユーザーエージェントを起動し、イベントの処理を許可するためにあらかじめ定義された期間だけアプリを動作させ続ける場合があり、どちらもバッテリー消費を引き起こします。ユーザーエージェントは、ユーザーが離れた後のウェブサイトによるリソース使用を制限するために、これらのイベントの継続時間と頻度に上限を設けるべきです。

大きなリソースは、background fetchBackgroundFetchManager インターフェースを介して登録することでダウンロードするべきです。

加えて、ユーザーエージェントは origin に対するユーザーのエンゲージメントや、データ節約モードなどデータ消費を一時的に抑えるユーザーの意思表示を考慮して、periodicsync events の頻度を調整するべきです。

7. アルゴリズム

7.1. 定期同期登録の処理

ユーザーエージェントが開始したとき、以下の手順を並列で実行します:
  1. 次の処理を繰り返します:

    1. minimum periodic sync interval across origins を待ちます。

    2. firedPeriodicSync を false にします。

    3. firedPeriodicSync が false の間:

      1. ユーザーエージェントが定義する一定時間を待ちます。

        注: これは異なる periodic sync registrations の同期を単一のデバイス起動にまとめるために使えます。

      2. online になるまで待ちます。

      3. 未だunregisteredでない各service worker registration registrationについて、 以下の手順をキューに追加し、registrationperiodic sync 処理キューに追加する:

        1. originorigin とします。これは periodicSyncRegistrationservice worker registration に関連付けられています。

        2. time of last fire[origin] + effective minimum sync interval for origin(origin) が現在時刻より大きい場合、continue します。

        3. registrationactive periodic sync registrations にある各 periodic sync registration periodicSyncRegistration について:

          1. state が "pending" でない場合、continue します。

          2. periodicSyncRegistrationanchor time + periodicSyncRegistrationminimum interval が現在時刻より大きい場合、continue します。

          3. firedPeriodicSync を true に設定します。

          4. periodicsync event を発火 します(対象: periodicSyncRegistration)。

7.2. 権限取り消しへの対応

name "periodic-background-sync" の権限が origin origin に対して取り消された場合、ユーザーエージェントは次の手順を periodic sync processing queue にエンキューしなければなりません:

  1. active periodic sync registrations に含まれる各 periodic sync registration registration について、その service worker registrationorigin と同じ origin に関連付けられているものを対象とします:

    1. active periodic sync registrations から registration を削除します。

8. API の説明

8.1. ServiceWorkerGlobalScope インターフェースへの拡張

partial interface ServiceWorkerGlobalScope {
    attribute EventHandler onperiodicsync;
};

8.2. ServiceWorkerRegistration インターフェースへの拡張

ServiceWorkerRegistration/periodicSync

In only one current engine.

FirefoxNoneSafariNoneChrome80+
OperaNoneEdge80+
Edge (Legacy)NoneIENone
Firefox for AndroidNoneiOS SafariNoneChrome for Android80+Android WebView80+Samsung Internet13.0+Opera MobileNone
[Exposed=(Window,Worker)]
partial interface ServiceWorkerRegistration {
  readonly attribute PeriodicSyncManager periodicSync;
};
A ServiceWorkerRegistration has a periodic sync manager (a PeriodicSyncManager).

The periodicSync 属性の getter はコンテキストオブジェクトの periodic sync manager を返さなければならず、初期値は新しい PeriodicSyncManager で、その service worker registration はコンテキストオブジェクトの context objectservice worker registration になります。

8.3. PeriodicSyncManager インターフェース

PeriodicSyncManager

In only one current engine.

FirefoxNoneSafariNoneChrome80+
Opera67+Edge80+
Edge (Legacy)NoneIENone
Firefox for AndroidNoneiOS SafariNoneChrome for Android80+Android WebView80+Samsung Internet13.0+Opera Mobile57+
[Exposed=(Window,Worker)]
interface PeriodicSyncManager {
    Promise<undefined> register(DOMString tag, optional BackgroundSyncOptions options = {});
    Promise<sequence<DOMString>> getTags();
    Promise<undefined> unregister(DOMString tag);
};

dictionary BackgroundSyncOptions {
    [EnforceRange] unsigned long long minInterval = 0;
};
A PeriodicSyncManager has a service worker registration (a service worker registration).

PeriodicSyncManager/register

In only one current engine.

FirefoxNoneSafariNoneChrome80+
Opera67+Edge80+
Edge (Legacy)NoneIENone
Firefox for AndroidNoneiOS SafariNoneChrome for Android80+Android WebView80+Samsung Internet13.0+Opera Mobile57+

メソッド register(tag, options) が呼び出されたとき、必ず新しい Promise promise を返し、次の手順を periodic sync processing queue にエンキューします:

  1. serviceWorkerRegistration を、コンテキストオブジェクトに関連付けられた service worker registration とします。

  2. serviceWorkerRegistrationactive worker が null の場合、reject して promiseInvalidStateError で拒否し、手順を中止します。

  3. PermissionStatePermissionDescriptorname "periodic-background-sync" に対して granted でない場合、reject して promiseNotAllowedError で拒否し、手順を中止します。

  4. ブール値 isBackground を true にします。

  5. serviceWorkerRegistrationservice worker clients の各 client について:

    1. clientframe type が "top-level" または "auxiliary" の場合、isBackground を false に設定します。

  6. isBackground が true の場合、reject して promiseInvalidAccessError で拒否し、手順を中止します。

  7. currentRegistration を、serviceWorkerRegistrationactive periodic sync registrations にある、periodic sync registration の中で tagtag と等しいものがあればそれに設定し、なければ null とします。

  8. currentRegistration が null の場合:

    1. 新しい periodic sync registrationnewRegistration として作成します。

    2. newRegistrationtagtag に設定します。

    3. newRegistrationminimum intervaloptionsminInterval メンバに設定します。

    4. newRegistrationstate を "pending" に設定します。

    5. newRegistrationservice worker registrationserviceWorkerRegistration に設定します。

    6. newRegistrationanchor time を現在時刻を表すタイムスタンプに設定します。

    7. newRegistrationserviceWorkerRegistrationactive periodic sync registrations に追加します。

    8. Resolve して promise を完了させます。

  9. そうでない場合(既存の登録がある場合):

    1. currentRegistrationminimum intervaloptionsminInterval と異なる場合:

      1. currentRegistrationminimum intervaloptionsminInterval に設定します。

    2. それ以外で、もし currentRegistrationstate が "firing" の場合、serviceWorkerRegistrationstate を "reregistered-while-firing" に設定します。

    3. Resolve して promise を完了させます。

PeriodicSyncManager/getTags

In only one current engine.

FirefoxNoneSafariNoneChrome80+
Opera67+Edge80+
Edge (Legacy)NoneIENone
Firefox for AndroidNoneiOS SafariNoneChrome for Android80+Android WebView80+Samsung Internet13.0+Opera Mobile57+

メソッド getTags() が呼び出されたとき、必ず新しい Promise promise を返し、次の手順を periodic sync processing queue にエンキューします:

  1. serviceWorkerRegistration を、コンテキストオブジェクトに関連付けられた service worker registration とします。

  2. currentTags を新しい list とします。

  3. serviceWorkerRegistrationactive periodic sync registrations の各 registration について、append を使って registrationtagcurrentTags に追加します。

  4. Resolve して promisecurrentTags で完了させます。

PeriodicSyncManager/unregister

In only one current engine.

FirefoxNoneSafariNoneChrome80+
Opera67+Edge80+
Edge (Legacy)NoneIENone
Firefox for AndroidNoneiOS SafariNoneChrome for Android80+Android WebView80+Samsung Internet13.0+Opera Mobile57+

メソッド unregister(tag) が呼び出されたとき、必ず新しい Promise promise を返し、次の手順を periodic sync processing queue にエンキューします:

  1. serviceWorkerRegistration を、サービスワーカー登録であり、コンテキストオブジェクトPeriodicSyncManager に関連付けられているものとする。

    1. currentRegistration を、serviceWorkerRegistration有効な periodic sync 登録の中から、その tagtag と等しい periodic sync 登録(存在しない場合は null)とする。

    2. もし currentRegistration が null でなければ、currentRegistrationserviceWorkerRegistration有効な periodic sync 登録 から削除する。

    3. promise を解決する。

8.4. periodicsync イベント

PeriodicSyncEvent/PeriodicSyncEvent

現在、1つのエンジンのみでサポートされています。

FirefoxなしSafariなしChrome80+
Opera67+Edge80+
Edge (レガシー)なしIEなし
Android 版 FirefoxなしiOS SafariなしAndroid 版 Chrome80+Android WebView80+Samsung Internet13.0+Opera Mobile57+

PeriodicSyncEvent

現在、1つのエンジンのみでサポートされています。

FirefoxなしSafariなしChrome80+
Opera67+Edge80+
Edge (レガシー)なしIEなし
Android 版 FirefoxなしiOS SafariなしAndroid 版 Chrome80+Android WebView80+Samsung Internet13.0+Opera Mobile57+
dictionary PeriodicSyncEventInit : ExtendableEventInit {
    required DOMString tag;
};

[Exposed=ServiceWorker]
interface PeriodicSyncEvent : ExtendableEvent {
    constructor(DOMString type, PeriodicSyncEventInit init);
    readonly attribute DOMString tag;
};

PeriodicSyncEvent/tag

現在、1つのエンジンのみでサポートされています。

FirefoxなしSafariなしChrome80+
Opera67+Edge80+
Edge (レガシー)なしIEなし
Android 版 FirefoxなしiOS SafariなしAndroid 版 Chrome80+Android WebView80+Samsung Internet13.0+Opera Mobile57+
PeriodicSyncEventtagtag)を持ちます。 tag 属性は初期化時に設定された値を返さなければなりません。

8.4.1. periodicsync イベントを発火する

注記: ユーザーエージェントは、PeriodicSyncEvent のライフタイム延長および実行時間に対し、一般的な ExtendableEvent よりも厳しい制限時間を課す場合があります。特に、PeriodicSyncEvent の再試行には大幅に短いタイムリミットが設けられる場合があります。
periodicsync イベントを発火するために、periodic sync registration registration について、ユーザーエージェントは以下の手順を実行しなければなりません:
  1. serviceWorkerRegistrationregistrationservice worker registration とします。

  2. もし registrationserviceWorkerRegistration有効な periodic sync registration に含まれていなければ、これらの手順を中止します。

  3. Assert: registrationstate は "pending" です。

  4. retryCount を 0 にします。

  5. registrationstate を "firing" に設定します。

  6. 次の間、繰り返します:

    1. continue を false にします。

    2. success を false にします。

    3. ファンクショナルイベント "periodicsync" を PeriodicSyncEvent を用いて serviceWorkerRegistration 上で、tagregistrationtag を設定して発火します。dispatchedEventExtendableEvent)を発火した periodicsync イベント とし、dispatchedEvent で以下の手順を実行します:

    4. waitUntilPromise を、すべてを待機 した dispatchedEventライフタイム延長プロミス の結果とします。

    5. waitUntilPromise成功時 には以下を実行:

      1. success を true にします。

      2. continue を true にします。

    6. waitUntilPromise失敗時 には以下を実行:

      1. continue を true にします。

    7. 並列で:

      1. continue が true になるまで待機します。

      2. originregistrationorigin とします。

      3. もし success が true ならば、キー origin に対する 前回発火時刻 を現在時刻に更新します。

      4. success が true、または retryCount最大リトライ回数 を超えた場合、または registration の state が "reregistered-while-firing" なら、以下を実行します:

        1. registrationstate を "pending" に設定します。

        2. registrationアンカータイム を現在時刻のタイムスタンプに設定します。

        3. これらの手順を中止します。

    8. retryCount をインクリメントします。

    9. retryCount に基づいた短いバックオフ時間待機します。

適合性

文書の慣例

適合要件は、記述的な主張と RFC 2119 の用語を組み合わせて示されています。 この文書の規範的な部分で “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, “OPTIONAL” のキーワードは RFC 2119 に記載されている通りに解釈するものとします。 ただし、可読性のため、これらの単語は本仕様ではすべて大文字で表記されません。

この仕様書内のテキストはすべて規範的です。明示的に非規範的と示されたセクション、例、注記を除きます。[RFC2119]

この仕様の例は “for example” との導入文、または class="example" により規範テキストと区別されています。以下のようになります:

これは情報提供例のひとつです。

情報提供用の注記は "Note" で始まり、class="note" で規範テキストと区別され、下記のようになります:

注記: これは情報提供用の注記です。

適合するアルゴリズム

アルゴリズムの一部として命令形で記述されている要件(例えば "先頭からすべての空白文字を削除する" や "false を返し、これらの手順を中止する" など)は、そのアルゴリズムの冒頭で使われているキーワード("must", "should", "may" など)に従って解釈されます。

アルゴリズムまたは特定手順として記述された適合要件は、同等の結果となる限り任意の方法で実装可能です。 特に本仕様で定義しているアルゴリズムは理解しやすいように作成されており、高速性を意図していません。 実装者は最適化を推奨します。

索引

この仕様によって定義された用語

参照により定義される用語

参考文献

規範的な参考文献

[BACKGROUND-FETCH]
Background Fetch. cg-draft. URL: https://wicg.github.io/background-fetch/
[DOM]
Anne van Kesteren. DOM Standard. Living Standard. URL: https://dom.spec.whatwg.org/
[HTML]
Anne van Kesteren; et al. HTML Standard. Living Standard. URL: https://html.spec.whatwg.org/multipage/
[INFRA]
Anne van Kesteren; Domenic Denicola. Infra Standard. Living Standard. URL: https://infra.spec.whatwg.org/
[PERMISSIONS]
Mounir Lamouri; Marcos Caceres; Jeffrey Yasskin. Permissions. 2020年7月20日. WD. URL: https://www.w3.org/TR/permissions/
[RFC2119]
S. Bradner. Key words for use in RFCs to Indicate Requirement Levels. 1997年3月. Best Current Practice. URL: https://tools.ietf.org/html/rfc2119
[SERVICE-WORKERS-1]
Alex Russell; et al. Service Workers 1. 2019年11月19日. CR. URL: https://www.w3.org/TR/service-workers-1/
[WEB-BACKGROUND-SYNC]
Web Background Synchronization. cg-draft. URL: https://wicg.github.io/background-sync/spec/
[WebIDL]
Boris Zbarsky. Web IDL. 2016年12月15日. ED. URL: https://heycam.github.io/webidl/

IDL 索引

partial interface ServiceWorkerGlobalScope {
    attribute EventHandler onperiodicsync;
};

[Exposed=(Window,Worker)]
partial interface ServiceWorkerRegistration {
  readonly attribute PeriodicSyncManager periodicSync;
};

[Exposed=(Window,Worker)]
interface PeriodicSyncManager {
    Promise<undefined> register(DOMString tag, optional BackgroundSyncOptions options = {});
    Promise<sequence<DOMString>> getTags();
    Promise<undefined> unregister(DOMString tag);
};

dictionary BackgroundSyncOptions {
    [EnforceRange] unsigned long long minInterval = 0;
};

dictionary PeriodicSyncEventInit : ExtendableEventInit {
    required DOMString tag;
};

[Exposed=ServiceWorker]
interface PeriodicSyncEvent : ExtendableEvent {
    constructor(DOMString type, PeriodicSyncEventInit init);
    readonly attribute DOMString tag;
};