⏲️

Beacon送信の信頼性を向上させるためのfetchLater APIという提案

2023/12/04に公開

※この記事はCybozu Frontend Advent Calendar 2023の4日目の記事です。

fetchLater APIとは

fetchLater APIは現在提案・策定が進められているAPIです。このAPIはユーザがページを離れたときにデータ(以下Beacon)を送信する際の信頼性(reliability)の向上を目的として提案されています。初期にはPendingBeacon APIという名で提案されていました。

fetchLater APIはChrome 120でDev Trial(Origin Trialが120 ~ 125)となっており、試せるようになりました。

fetchLater API - Chrome Platform Status

fetchLater APIの使用例

次のコードはfetchLater APIを使ってGETを行う単純な例です。

fetchLater('/send_beacon')

fetchLater()を実行するとブラウザはリクエストをキューに入れ、ページが破棄またはbfcacheからevictedされた(追い出された)ときにリクエストを送信します。

fetchLater APIは汎用的にリクエストを遅延させるためのAPIとしてデザインされています。

次のコードはfetchLater()を実行して60000ms後にリクエストを実行させる例です。

fetchLater({
  url: '/send_beacon'
  method: 'POST'
  body: getBeaconData(),
},{ activateAfter: 60000 });

※ 時間を指定できますが、ブラウザが実際にこの時間通りに実行することは保証されないようです。

# Defer a POST request for around 1 minute
NOTE: The actual sending time is unkown, as the browser may wait for a longer or shorter period of time, e.g., to optimize batching of deferred fetches.

ユーザがページを離れたときにBeaconを送りたい(beaconing)という需要

WebサイトやWebアプリケーションにおいて、おもに遠隔測定(telemetry)を目的としてユーザがページを離れたときにサーバに対してBeaconを送りたいという需要があります。遠隔測定を何のために行うかはそれぞれですが、いずれにしても遠隔測定のためにはBeaconの送信を確実に行うことが求められます。

しかしながら現在のWebにおいて、ユーザがページを離れたときにBeaconを送る手段の信頼性は低いものになっています。

"ページを離れたとき"をハンドリングする手段の信頼性が低い

現状おもに用いられている手段は、JavaScriptを使ったページライフサイクルのイベントに合わせてのBeacon送信です。送信するタイミングとしておもに次の4つのイベントが使われています。

  • unload
  • beforeunload
  • pagehide
  • visibilitychange
addEventListener("unload", (event) => {
  navigator.sendBeacon(url, JSON.stringify(data))
})

addEventListener("beforeunload", (event) => {
  navigator.sendBeacon(url, JSON.stringify(data))
})

addEventListener("pagehide", (event) => {
  navigator.sendBeacon(url, JSON.stringify(data))
})

addEventListener("visibilitychange", (event) => {
  if (document.visibilityState === 'hidden') {
    navigator.sendBeacon(url, JSON.stringify(data))
  }
})

同様の目的に使えそうなイベントが4つもありますが、これらはいずれも信頼性の面で問題があり、複数のイベントを併用したとしても約10%程度のBeaconが送信されることなく消えるというデータもあります。


ページイベントの信頼性
引用: https://www.speedkit.com/blog/unload-beacon-reliability-benchmarking-strategies-for-minimal-data-loss/

unloadbeforeunloadはいくつかのブラウザで完全に無視され、なにも実行されません。また、pagehidevisibilitychangeはモバイルブラウザでページが破棄されるシチュエーションなどによってはイベント自体が発火しないことや、互換性の問題からも信頼性が低い状態です。

現状の手段として最良とされているpagehidevisibilitychangeを併用した手段でも10回に1回程度はBeaconの送信が失敗するという信頼性の低さ、これを解決するための提案がfetchLater APIです。

PendingBeacon APIのOrigin Trialの計測データ

fetchLater APIの前身であるPendingBeacon APIはChromeの107から115でOrigin Trialが行われました。

PendingBeacon API (deprecated)

このTrialの期間でPendingBeacon APIを使ったユーザがページを離れたときにBeaconを送る際の信頼性がどの程度あるのかを計測してまとめたデータがSpeed Kitの記事にて公開されています。


PendingBeacon APIの信頼性
引用: https://www.speedkit.com/blog/unload-beacon-reliability-benchmarking-strategies-for-minimal-data-loss/

この計測ではPendingBeacon APIでBeaconの送信が98%完了できており、信頼性の高さがうかがえます。この計測結果から、fetchLater APIについても同様の信頼性が見込めるのではと考えられます。

おわりに

提案・策定中であるfetchLater APIについて紹介しました。

fetchLater APIについてはFirefoxやSafariなど、Chrome以外のブラウザについても好意的なpositionを表明しています。

https://github.com/mozilla/standards-positions/issues/703
https://github.com/WebKit/standards-positions/issues/85

Beaconの送信は長らく開発者を悩ませる問題としてありますが、より信頼性の高い手段が遠くないうちに各ブラウザで使えるようになるのが期待できそうです。

参考URL

サイボウズ フロントエンド

Discussion