はじめに
先日より試してみている機能の一つとして、アプリの設定や機能フラグを一元的に管理するためのサービスとしてAzure App Configurationというものがあります。
上のドキュメントを読んでもあまり嬉しさがわからないのですが、その嬉しさを理解するためにもSpring Bootアプリで試してみることにしました。今回はポーリングモデルを使用した動的な構成を試してみました。
これまで試した記事は以下の通り。
サンプル
例によってチュートリアルが用意されているのでそれを参考にします。
例によって幾つか注意点がありましたので、それらを記していきます。
ライブラリのバージョン
com.azure.spring:azure-spring-cloud-appconfiguration-config-web
が必要ということなので、build.gradle
に追記しておきます。追記する際、com.azure.spring:azure-spring-cloud-appconfiguration-config-web
のバージョンを確認しておきます。先日com.azure.spring:azure-spring-cloud-appconfiguration-config
を試したときには、2.5.0
だったのですが、執筆時点(2022年5月8日)では2.6.0
が出ていたので、両方のバージョンを合わせておきます。
実装
実装というほどでもないですが、src/main/resources/boostrap.properties
に以下の2行を追加します。
spring.cloud.azure.appconfiguration.stores[0].monitoring.enabled=true spring.cloud.azure.appconfiguration.stores[0].monitoring.triggers[0].key=sentinel
このとき、spring.cloud.azure.appconfiguration.stores[0].monitoring.triggers[0].key=sentinel
を記述していない場合はSpring Bootアプリの起動時に以下の例外をはいて起動に失敗します。
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'spring.cloud.azure.appconfiguration-com.azure.spring.cloud.config.properties.AppConfigurationProperties': Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: Triggers need to be set if refresh is enabled.
spring.cloud.azure.appconfiguration.stores[0].monitoring.triggers[0].key
の値に指定するのはAzure App Configurationの構成エクスプローラーで指定したキーとなります。ちなみに、この値をAzure App Configurationで設定したものとは違うもの(sentinel2とか)に指定した場合、Spring Bootアプリは以下の例外をはいて起動に失敗します。
com.azure.core.exception.ResourceNotFoundException: Setting not found.
試してみる
この状態でAzure App Configuration上の/application/config.message
の値を変更します。変更は3点リーダーをクリックしたら出てくるEditを押した画面にて実施します。
これだけだとダメで、spring.cloud.azure.appconfiguration.stores[0].monitoring.triggers[0].key
で指定したキーの値も変更します。
変更が完了後、少し(30秒ぐらい)待ってSpring Bootアプリにアクセスします。最初のアクセス時に/application/config.message
が変更されたことが検出されます。Spring Bootアプリのログにも、変更が検出されRefresh keys changed
と出力されていることがわかります。
2022-05-08 11:22:10.507 INFO 7265 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet' 2022-05-08 11:22:10.509 INFO 7265 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 2 ms 2022-05-08 11:27:07.580 INFO 7265 --- [ task-16] c.a.s.c.config.AppConfigurationRefresh : Configuration Refresh Event triggered by sentinel 2022-05-08 11:27:08.360 INFO 7265 --- [ task-16] b.c.PropertySourceBootstrapConfiguration : Located property source: [BootstrapPropertySource {name='bootstrapProperties-/application/https://xxxxxxxxxxxx.azconfig.io/'}] 2022-05-08 11:27:08.363 INFO 7265 --- [ task-16] o.s.boot.SpringApplication : No active profile set, falling back to 1 default profile: "default" 2022-05-08 11:27:08.367 INFO 7265 --- [ task-16] o.s.boot.SpringApplication : Started application in 0.784 seconds (JVM running for 312.312) 2022-05-08 11:27:08.417 INFO 7265 --- [ task-16] o.s.c.e.event.RefreshEventListener : Refresh keys changed: [config.message]
この段階ではブラウザの表示に変更はありません。
再度Spring Bootアプリにアクセスすることで/application/config.message
の値が反映され、ブラウザの表示が変更されます。
変更が検出される時間を短く/長くする
今回、変更が検出されるためにspring.cloud.azure.appconfiguration.stores[0].monitoring.triggers[0].key
で指定したキーの値の変更後30秒ほど待ちました。これは、com.azure.spring:azure-spring-cloud-appconfiguration-config-web
で設定されているspring.cloud.azure.appconfiguration.stores[0].monitoring.refresh-interval
という設定値のデフォルト値が30秒になっているためです。これを短くする/長くするにはsrc/main/resources/boostrap.properties
にて次のように記述すればよいです。
# 10秒に変更 spring.cloud.azure.appconfiguration.stores[0].monitoring.refresh-interval=10s
上記のように設定すると、10秒で変更が検出されるようになりました。
テストの時Azure App Configurationを参照しないようにする
ポーリングモデルを使用した動的な構成のテストは以上です。ここからは、少し発展的な話題です。
JUnitなどでテストを書いた時、Azure App Configurationを設定しなくてもJUnitのテストは動くようにしたい場合があります。このような場合はsrc/test/resources/bootstrap.properties
にて以下の記述をすればJUnitのテスト実行時にAzure App Configurationを参照することはなくなります。
spring.cloud.azure.appconfiguration.enabled=false
このときAzure App Configurationで設定する各種設定値を使ったテストをしたい場合は、以下の通り@SpringBootTest
のproperties
属性を使って設定してあげたらテストごとに異なった設定値のテストができてよいかなと思います。
@SpringBootTest(properties = "config.message=hogehoge") @AutoConfigureMockMvc public class HelloControllerTest { @Autowired private MockMvc mockMvc; @Test public void shouldReturnMessage() throws Exception { this.mockMvc.perform(get("/")) .andDo(print()) .andExpect(status().isOk()) .andExpect(content().string(containsString("Message:hogehoge"))); } }
サンプルソース
ここまでのソースです。