lambdaでSpring Bootで書かれたアプリケーションを15分に1回スケジュール実行しようとすると、1回目はうまくいくのだが、2回目以降以下のエラーになった。
{
"errorMessage": "Unable to register MBean [org.springframework.cloud.context.environment.EnvironmentManager@7bd6185a] with key 'environmentManager'; nested exception is javax.management.InstanceAlreadyExistsException: org.springframework.cloud.context.environment:name=environmentManager,type=EnvironmentManager",
"errorType": "org.springframework.jmx.export.UnableToRegisterMBeanException",
"stackTrace": [
"org.springframework.jmx.export.MBeanExporter.registerBeanNameOrInstance(MBeanExporter.java:625)",
"org.springframework.jmx.export.MBeanExporter.registerBeans(MBeanExporter.java:550)",
"org.springframework.jmx.export.MBeanExporter.afterSingletonsInstantiated(MBeanExporter.java:432)",
"org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:792)",
"org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:839)",
"org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:538)",
"org.springframework.boot.SpringApplication.refresh(SpringApplication.java:766)",
"org.springframework.boot.SpringApplication.createAndRefreshContext(SpringApplication.java:361)",
"org.springframework.boot.SpringApplication.run(SpringApplication.java:307)",
"jp.co.recruit.rtc.hoc.elbconnector.ElbConnectorMain.handleRequest(ElbConnectorMain.java:44)",
"sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)",
"sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)",
"sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)",
"java.lang.reflect.Method.invoke(Method.java:498)"
],
"cause": {
"errorMessage": "org.springframework.cloud.context.environment:name=environmentManager,type=EnvironmentManager",
"errorType": "javax.management.InstanceAlreadyExistsException",
"stackTrace": [
"com.sun.jmx.mbeanserver.Repository.addMBean(Repository.java:437)",
"com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.registerWithRepository(DefaultMBeanServerInterceptor.java:1898)",
"com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.registerDynamicMBean(DefaultMBeanServerInterceptor.java:966)",
"com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.registerObject(DefaultMBeanServerInterceptor.java:900)",
"com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.registerMBean(DefaultMBeanServerInterceptor.java:324)",
"com.sun.jmx.mbeanserver.JmxMBeanServer.registerMBean(JmxMBeanServer.java:522)",
"org.springframework.jmx.support.MBeanRegistrationSupport.doRegister(MBeanRegistrationSupport.java:195)",
"org.springframework.jmx.export.MBeanExporter.registerBeanInstance(MBeanExporter.java:678)",
"org.springframework.jmx.export.MBeanExporter.registerBeanNameOrInstance(MBeanExporter.java:615)",
"org.springframework.jmx.export.MBeanExporter.registerBeans(MBeanExporter.java:550)",
"org.springframework.jmx.export.MBeanExporter.afterSingletonsInstantiated(MBeanExporter.java:432)",
"org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:792)",
"org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:839)",
"org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:538)",
"org.springframework.boot.SpringApplication.refresh(SpringApplication.java:766)",
"org.springframework.boot.SpringApplication.createAndRefreshContext(SpringApplication.java:361)",
"org.springframework.boot.SpringApplication.run(SpringApplication.java:307)",
"jp.co.recruit.rtc.hoc.elbconnector.ElbConnectorMain.handleRequest(ElbConnectorMain.java:44)",
"sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)",
"sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)",
"sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)",
"java.lang.reflect.Method.invoke(Method.java:498)"
]
}
}
調べると、これはSpringがJMXを使うためのMBeanを登録してくれるのだが、ApplicationContextを作る度に登録される。
Lambdaのスケジュール実行では1回目と2回目以降は同一のJVM内で動作するようなので、1回に実行したときにMBeanを登録し、2回目に実行したときに同じMBeanを登録しようとしてエラーになっている模様。
これを回避するには、JMX自体を無効にしてしまえばMBeanは登録されない。
具体的にはapplication.propertiesに以下を追加すればOK。
spring.jmx.enabled=false