Spring Actuator のヘルスチェックリクエストのたびに DB にセッション情報が格納されてしまった件
現在、Spring Boot のアプリケーションでヘルスチェック用のエンドポイントに Spring Actuator を利用しています。 ただヘルスチェックリクエストのたびに DB にセッション情報が格納されてしまう問題がありました、 本記事はこれを解消するため原因調査を行った記録となります。
アプリケーション構成
- JDK
- Amazon Corretto 17
- Spring Boot 3.0
- Spirng Framework 6.0
- Spring Security 6.0
- Spring Session 3.0
- Spring Actuator 3.0
結論
Spring Session が提供するフィルターがセッション情報の永続化を行なっている。
org.springframework.session.web.http.SessionRepositoryFilter
そのため、SessionRepositoryFilter
より前に実行されるフィルター ExcludeSessionRepositoryFilter
を設定し、ヘルスチェックリクエストの場合にリクエスト属性に SessionRepositoryFilter が適用済みであると追加してあげればよい。
httpRequest.setAttribute("org.springframework.session.web.http.SessionRepositoryFilter.FILTERED", Boolean.TRUE);
以下、原因特定までの過程
1. Spring Security の Configuration を見直す
ざっと調べたところ認証周りがあやしかったので、Spring Security の Configuration を見直しましたが未認証の設定になっており特に問題はなかったです。
2. Spring Framework の DEBUG ログを眺めてみる
Spring Framework のログレベルを DEBUG にするとセッション作成時にスタックトレースを出してくれた。めちゃくちゃ便利!!
2023-07-04 23:21:03.113 [DEBUG] [http-nio-8080-exec-3] org.springframework.session.web.http.SessionRepositoryFilter$SessionRepositoryRequestWrapper: A new session was created. To help you troubleshoot where the session was created we provided a StackTrace (this is not an error). You can prevent this from appearing by disabling DEBUG logging for org.springframework.session.web.http.SessionRepositoryFilter.SESSION_LOGGER java.lang.RuntimeException: For debugging purposes only (not an error) at org.springframework.session.web.http.SessionRepositoryFilter$SessionRepositoryRequestWrapper.getSession(SessionRepositoryFilter.java:313) ~[spring-session-core-3.0.1.jar:3.0.1] ...
スタックトレースを遡ることで、org.springframework.session.web.http.SessionRepositoryFilter
がセッション作成をしていることが分かった。
Spring Security は特に関係なかった。。
3. SessionRepositoryFilter を特定のパスの時だけ無効にする方法を調べる
Is it possible to exclude some url from the SessionRepositoryFilter · Issue #244 · spring-projects/spring-session · GitHub の issue が見つかって解決!
Maven + Tomcat 8.0 の開発環境を構築する
Maven プロジェクトを Tomcat 8.0 で動かす環境を用意する必要があったので構築手順をメモしておきます。 モチベーションとしては、がっつり開発するわけではなく、ざっくりと動作確認できればいいです。
開発環境
IDE はお好きなもので
構築手順
Docker で Tomcat コンテナを起動する
まずは docker-compose.yml
を用意します。
version: 2 services: tomcat: image: tomcat:8.0 container_name: tomcat-container ports: - 8080:8080
次にコンテナを起動します。
docker-compose up -d
これで、http://localhost:8080
にアクセスすると Tomcat が起動しているのが分かります。
Maven プロジェクトのビルド
pom.xml
などについては省略します。
mvn clean package
Tomcat にデプロイ
Tomcat コンテナの /usr/local/tomcat/webapps/
に war ファイルをコピーするだけでデプロイできます。
docker cp target/sample_app-1.0-SNAPSHOT.war tomcat-container:/usr/local/tomcat/webapps/sample-app.war
http://localhost:8080/sample-app/*
にアクセスするとデプロイしたアプリを確認できます。
補足
Tomcat 7 系で動かしたい場合
pom.xml
に tomcat7-maven-plugin
を追加して、以下のコマンドで簡単にデプロイできます。
mvn tomcat7:run