Webアプリケーションにおける排他制御の問題(×ボタンへの対処)

WEBアプリケーションにおいて、ある処理をさせている最中にDBのレコードをロックしておきたいことはよくある。帳票情報の編集画面で帳票レコードをロックしておいて、処理が終了するとロックを解除する、という風にしたい。

大体の場合、ページのフォーム中に「閉じる」「中止」「戻る」などのボタンを用意しておいて、ボタンへのクリックをトリガーにしてロックの解除処理→元の画面に遷移って処理を行うんだけれど、WebブラウザをインターフェースとするWebアプリケーションにはやっかいな問題がある。

ブラウザウィンドウの×ボタンなんかでユーザーが正規の(?)手段を使わないでブラウザを閉じてしまうことがあるから。当然一般ユーザーが使うシステムだとこういった操作にも対応しないといけない。しかしこの問題、Webを調べてみても多くの人が苦しんでる問題らしい。


まずはHTMLのUnloadイベントをトラップし、ロックの解除処理をすればよさそうな気がする。

<script language="JavaScript">
<!--
 function fnc_onUnload() {
  // ロック解除処理
  alert('トムの身にいったい何が起こったのか!?') 
 }
// -- >
</script>


<BODY onUnload="fnc_onUnload()";>
 <!-- この後、トムの身にとんでもない出来事が(ウワァァー →[CM] -->

しかし困ったことにUnloadイベントはウィンドウを閉じたとき以外にも発生する

  • リロードを行った時
  • 他のページに遷移する時

のでこれでブラウザが閉じられたと判断してロック解除を行ってしまうと困ったことになる。


そもそも、Webアプリケーションにおいて処理が終了されるパターンって

  1. 処理が終了する。
  2. Webフォームの「ログアウト」「閉じる」などのボタンを押される
  3. ブラウザの×ボタンを押される
  4. ファイル(F)→閉じる(C)を選ばれる
  5. Ctrl+Wのショートカットで(ry
  6. 他のページへ遷移する
  7. ブラウザのプロセスがタスクマネージャから強制終了される
  8. ブラウザがクラッシュする
  9. PCの電源が停電などでいきなり落ちる
  10. PCの電源がコンセントを抜かれいきなり(ry

などなど想定できる原因は無数にあり、そもそもServletServletコンテナはサーバーサイドで動作するため、クライアントサイドのブラウザ閉じられたことを、基本的には感知することが出来ない。清く放置プレイと行きたいところだけど、ユーザー側の要求は厳しい orz

とりあえずWebを調べまわってみてevent.clientX/clientYの値を見てやる方法を発見。
IE6以下限定だけどウィンドウが閉じられた場合には-8900以下の特殊な値が入るらしい。

 <script language="JavaScript">
 <!--
  function fnc_onUnload() {
   
   alert("event.clientX:" + event.clientX + " , " + "event.clientY:" + event.clientY);
   if(event.clientX <= -8900 || event.clientY <= -8900 ) {
     //ロック解除処理
     alert("トムは全身の7割を火傷していて、とても危険な状態でした");
   }
  }
 // -- >
 </script>

WinXP SP2+MSIE6.0の環境ではちゃんと動いた。
ただ、ブラウザを最小化した状態で閉じようとすると
clientX:33782, clientY:32247
みたいな状態になってしまう.。
というわけで

 <script language="JavaScript">
 <!--
  function fnc_onUnload() {
   
   alert("event.clientX:" + event.clientX + " , " + "event.clientY:" + event.clientY);
   if(event.clientX <= -8900 || event.clientY <= -8900 || event.clientX >= 32000 || event.clientY >= 32000) {
     //ロック解除処理
     alert("3ヵ月後・・・そこには元気な姿でかけまわるトムの姿が!");
   }
  }
 // -- >
 </script>
 //元気になったトムがピザになってる

書き直してみた。これでとりあえず漏れの環境のIEでは期待していた動作をするようにはなった。ちなみにFirefox2.0では当然のごとく駄目だったw
この方法の問題は
・画面の解像度によってClientX、ClientYの値は大きく変わってくる。
・IE6以下専用(IE7では不可能らしい)
JavaScript無効にされてたらアウト
といったところ。結局バリバリ実装系依存になってしまうんだよなあ。いまいち面白くないけどWebアプリケーションの宿命としてあきらめるしかないのか。

いっそ閉じるボタンを使用不能に出来るJavaScriptがあれば・・・とか思ったけど、「閉じるボタン不可」「ウィンドウ位置変更不可」「戻るボタン使用不可」なんてユーザーから見ればウザい以外の何者でもないからなぁ。ふとすると悪質なブラクラにもなりかねないし。

結局、タイムアウト時間を設定して一定時間非アクティブなロックレコードは強制的にロック解除させるのが一番現実的な方法か。