基本がきちんとわかっておらず、不具合を発生させてしまったケースとして、恥を承知で記録しておきます。
トラブル内容
リリースしたアプリケーションが、ここ数日間、やたらと「ViewExpiredException」が多発しまくるようになってしまいました。
ソフトウェアは、JavaEE7(glassfish4.1)、JSF2.2+Primefaces5.1です。
発生している画面は、ログイン画面や複数の入力画面で、一定ではありません。
時間帯もまばら。う~ん、これには参りました。
原因発見
サイトをいろいろと確認していると、JavaEE Server の「STATE_SAVING_METHOD」が「server」の設定の場合、そのデフォルトのview情報保持数が15であるらしいということを発見。
jsf 2 - How and when is a view scope bean destroyed in JSF? - Stack Overflow
session - How can I set the view timeout? - Stack Overflow
15を超えたview Scopeの接続数があった場合に、一番最初のview情報が消失してしまっていたということか・・・!
これって、基本の中の基本のような気がしますが。。。
設定変更
まずは、web.xmlに下記のような設定を追加して、動作確認。すると4つ目のviewを起動した後に、最初のviewを実行しみると、即効で「ViewExpiredException」が発生しました!
<context-param> <param-name>javax.faces.STATE_SAVING_METHOD</param-name> <param-value>sever</param-value> </context-param> <context-param> <param-name>com.sun.faces.numberOfViewsInSession</param-name> <param-value>3</param-value> </context-param> <context-param> <param-name>com.sun.faces.numberOfLogicalViews</param-name> <param-value>3</param-value> </context-param>
間違いない!
元々のweb.xmlには、javax.faces.STATE_SAVING_METHOD自体、定義しておらず、未定義の場合には、serverになるようです。さらにviewの保有可能な数もデフォルト15になり、利用者のアクセスが増加してきたことで、起こるべくして起きたという話だったのです。
しかし、viewの設定値をどの程度にすれば良くわからず、「javax.faces.STATE_SAVING_METHOD」の設定を「client」で試してみることにしました。
<context-param> <param-name>javax.faces.STATE_SAVING_METHOD</param-name> <param-value>client</param-value> </context-param>
この設定は注意が必要とのことで、下記のサイトによりますと、次の通り書かれておりました。
保存場所としてクライアントを指定した場合、UIコンポーネントの状態がシリアライズされた形式で隠しパラメタに保存されるため、以下のセキュリティ上の問題があります。
・悪意を持った第三者が、ブラウザに残ったキャッシュから隠しパラメタを読み出し、デコードすることによって画面に入力されたデータを読み取る可能性があります。
・悪意を持った第三者が、シリアライズしたデータを作成しリクエストパラメタとして送信することで、任意のUIコンポーネントツリーをサーバ側に作成する可能性があります。http://software.fujitsu.com/jp/manual/manualfiles/M050000/J2X11200/01/jsfgd07/jsfgd041.html
今回は、閉ざされた環境ですので、「client」での状態保存にしましたが、セキュリティ上、かなり危険な状態であることがわかりました。
しかしながら、clientの設定のほうが、serverよりも多少、レスポンスがよくなったように思います。
しばらく、様子を見てみようと思います。
反省
最初のプロトタイプ開発の時点で、こういう原則をきちんとわかっていないことが大問題ではありますが、JMeterなどでの負荷テストを疎かにしてしまったことも反省点のひとつであります。
これもいい経験として、前進していくしかありませんね!