ServiceWorker as a Service, または Universal ServiceWorker という発想

ServiceWorker とは本質的に リクエスト&レスポンスモデルであるので、それをサーバーサイドで実装で一種のサーバーロジックとして動かしてしまって良いはずだ ー

という発想に目から鱗だったので、ちょっと考えてみたいと思う。

www.publickey1.jp

ここで試せる。

https://cloudflareworkers.com/#a9bc9ef6b4248289c71518581df30bc7:https://tutorial.cloudflareworkers.com

Cloudflare はCDN業者なので、 それに特化して Service Worker as a Service みたいな表現はしていないが、実態としてはサーバーサイド ServiceWorker だ。Fastly では varnish のミドルウェアなどでキャッシュ破棄設定のロジックやリダイレクトを書いていたが、それが ServiceWorker という体を取っている(ように見える)。

ちゃんと使い込んでいないので、おそらくだが、 cache オブジェクトの実装が cloudflare の asset cache の実装にそのままつながっていて、そこでキャッシュ破棄、構築命令に翻訳されているのだろう。


追記: 実際はレスポンスを書き換えるだけで、まだキャッシュ実装はないが、やりたいとのこと


Cloudflare の手法で優れているのは、現状、すべてのブラウザが Service Worker を実装しているわけではない(というかIEのことだが)ので、将来的には標準的な手法になるはずの中間層を用意したことで、たとえばpush イベントも(Safariであっても) をサーバーサイドで溜め込んで置いたり出来る。また、クライアント用 Service Worker と密に連携したスクリプトも配信できる。ビジネス的にもストレージサイズやイベントドリブンなエンドポイントの実行回数で課金できる。

イベントドリブン標準としての ServiceWorker

ミドルウェアでなんでもできる、という点で AWS Lambda や Google Cloud Function と同じようなものとして使うことが可能だろう。FaaS の1スペックとして、ServiceWorker as a Service という形式はアリだろうか。

cloudflare の チュートリアルで配布されてるコードはこんな感じ。

addEventListener('fetch', event => {
  event.respondWith(fetchAndLog(event.request))
})

/**
 * Fetch and log a given request object
 * @param {Request} request
 */
async function fetchAndLog(request) {
  console.log('Got request', request)
  const response = await fetch(request)
  console.log('Got response', response)
  return response
}

普通の service worker のコードだ。普通の。

毎度 Lambda と Cloud Function を使ってて思うのは、いまいち Node 側からのインターフェースが仕様化・共通化されていないので、毎回ベンダロックインされたコードを書くことになってしまっている。それぐらいだったら一応は仕様がW3Cではっきりしている ServiceWorker の仕様を使うのは筋悪ではない、と思う。

しかしどうせ各プラットフォームが独自な名前空間を持ってイベントを生やしてくる。Cloudflare もその方向を最初検討したようだし、それ自体は現実的なユースケースを踏まえると必要だと思う。実際ユニバーサルな ServiceWorker というものは、なんらかの抽象化層を経ないと到達し得ないだろう。

また、express で cluster モジュールなどを使ってOSSなサーバーサイドServiceWorkerを実装するのは、そこまで難しくなさそうに見える。Open FaaSなどとも方向性が同じになる。

なので、方向性としては歓迎したいが、大きなプレーヤーが標準化に向けて動いてくれないと難しそう。