はんけトケのロゴタイプ
これは何?
開発ノート

共有メモリーによるワーカー制御

計算待ち行列

はんけトケの地図上のピンを、半径最大・データ粒度最小くらいでグリグリ動かすと、計算が追いつかずに統計が遅れて表示されることがあります。

計算が遅れてしまうこと自体は機器の性能次第で仕方ありません。 問題は、その計算中に次の計算要求が発行され、さらにまた発行されて、と計算待ち行列がどんどん伸びてしまうこと。 操作をやめても、待ち行列をさばき終えるまで延々と計算が続いてしまうのです。

これはみっともないだけでなく、最新の(最後の)結果が出るまで待たされてしまうことになり、体験を悪化させます。

ワーカーと制限

はんけトケの統計処理は、操作性に悪影響しないようワーカーつまり別スレッドで実行しています。 そのワーカーがまだ計算中に次の計算が要求されたら、現在の計算を中断するとか、逆に要求のほうを蹴る(あるいはそもそも要求しない)なりすれば、計算待ち行列が伸びることはないはず。

簡単なスレッド同期制御のようですが、JavaScriptにおいてはあまり簡単ではありません。 JavaScriptのワーカーは各々独立した空間で動作し、限られた手段でしか互いに連絡できないのです。

ワーカー間の連絡にはメッセージを送受信するのが基本ですが(postMessage())、これは相手の処理中に割り込むことができないようです。 処理中の相手に情報を伝えるには、専用のメモリー領域を共有し(共有メモリー)、その内容を書き換えて相手に見てもらう必要があります。

しかし、肝心のその共有メモリーは、あるハッキング攻撃に対する防衛策として使用が原則禁じられています。 なんと、それでは計算を止めることはできないのでしょうか。

制限解除

しかし裏を返せば、くだんの攻撃に対して安全でさえあれば禁じる必要はないわけで。 実は、サーバーが次の2つをHTTP応答ヘッダーに設定するだけで、共有メモリーへの制限が解除されます。

  • Cross-Origin-Opener-Policy: same-origin
  • Cross-Origin-Embedder-Policy: require-corp

これらはセキュリティーをより強化する指示なのでご心配なく。 この件について詳しくは、MDNウェブ文書「SharedArrayBuffer」の項を参照のこと。

これで晴れて共有メモリーを使えるようになり、計算待ち行列を解消することができました。

別の方法

晴れて、と行きがかり上書いたものの、うちのサーバーはセキュリティーに関するHTTP応答ヘッダーはもともとちゃんと設定していました。 ただ共有メモリーの使い方に気づいただけです。 HTTP応答ヘッダーによるセキュリティーは、だれでも簡単にできる基本的な安全策なので、設定できるならしておかないと損。

しかし、諸般の事情で設定できないケースもあるでしょう。 ありがちなのは広告を入れている場合。 セキュリティーが厳しいと、広告のような不特定の第三者のリソースを埋め込んだり通信させたりもできなくなってしまうのです。

ともあれそうした場合には、ワーカーをまるごと削除することで処理を中断させるという、制限無用の強引な奥の手があります。 短時間に繰り返すのはさすがに苦しそうですが、局面によっては使えるかもしれません。

用語・注釈

ワーカー(ウェブワーカー)
JavaScriptにおけるバックグラウンド実行スレッド。
共有メモリーについて
たとえ制限解除しても、共有メモリーはサービスワーカーとは共有できないことに注意。 サービスワーカーは一般のワーカーとエージェントクラスターが異なるため。