From ecd86474b2df919a97799a4cdaa770453bda23dd Mon Sep 17 00:00:00 2001 From: Alexander Dinauer Date: Wed, 13 Dec 2023 07:49:39 +0100 Subject: [PATCH 1/3] make sentrys SchedulerFactoryBeanCustomizer run first so users can override what it does --- .../spring/jakarta/checkin/SentryQuartzConfiguration.java | 3 +++ .../io/sentry/spring/checkin/SentryQuartzConfiguration.java | 3 +++ 2 files changed, 6 insertions(+) diff --git a/sentry-spring-jakarta/src/main/java/io/sentry/spring/jakarta/checkin/SentryQuartzConfiguration.java b/sentry-spring-jakarta/src/main/java/io/sentry/spring/jakarta/checkin/SentryQuartzConfiguration.java index eb396c9692..e4e9104eb0 100644 --- a/sentry-spring-jakarta/src/main/java/io/sentry/spring/jakarta/checkin/SentryQuartzConfiguration.java +++ b/sentry-spring-jakarta/src/main/java/io/sentry/spring/jakarta/checkin/SentryQuartzConfiguration.java @@ -5,6 +5,8 @@ import org.springframework.boot.autoconfigure.quartz.SchedulerFactoryBeanCustomizer; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.core.Ordered; +import org.springframework.core.annotation.Order; @Configuration(proxyBeanMethods = false) @Open @@ -12,6 +14,7 @@ public class SentryQuartzConfiguration { @Bean + @Order(Ordered.HIGHEST_PRECEDENCE) public SchedulerFactoryBeanCustomizer schedulerFactoryBeanCustomizer() { return new SentrySchedulerFactoryBeanCustomizer(); } diff --git a/sentry-spring/src/main/java/io/sentry/spring/checkin/SentryQuartzConfiguration.java b/sentry-spring/src/main/java/io/sentry/spring/checkin/SentryQuartzConfiguration.java index 640507dd7c..a093dba272 100644 --- a/sentry-spring/src/main/java/io/sentry/spring/checkin/SentryQuartzConfiguration.java +++ b/sentry-spring/src/main/java/io/sentry/spring/checkin/SentryQuartzConfiguration.java @@ -5,6 +5,8 @@ import org.springframework.boot.autoconfigure.quartz.SchedulerFactoryBeanCustomizer; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.core.Ordered; +import org.springframework.core.annotation.Order; @Configuration(proxyBeanMethods = false) @Open @@ -12,6 +14,7 @@ public class SentryQuartzConfiguration { @Bean + @Order(Ordered.HIGHEST_PRECEDENCE) public SchedulerFactoryBeanCustomizer schedulerFactoryBeanCustomizer() { return new SentrySchedulerFactoryBeanCustomizer(); } From 78ae0369cf0b35eb3f49465f2776f50d6ce1f6d1 Mon Sep 17 00:00:00 2001 From: Alexander Dinauer Date: Wed, 13 Dec 2023 08:37:12 +0100 Subject: [PATCH 2/3] changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2ee5e78243..f4132eff66 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,8 @@ ### Fixes - Send breadcrumbs and client error even without transactions ([#3087](https://github.com/getsentry/sentry-java/pull/3087)) +- SchedulerFactoryBeanCustomizer now runs first so user customization is not overridden ([#3095](https://github.com/getsentry/sentry-java/pull/3095)) + - If you are setting global job listeners please also add `SentryJobListener` ### Dependencies From 59b926c429d19d3b8999c7e2d6eb0fe8f0860645 Mon Sep 17 00:00:00 2001 From: Alexander Dinauer Date: Tue, 19 Dec 2023 06:42:06 +0100 Subject: [PATCH 3/3] add tests --- .../jakarta/SentryAutoConfigurationTest.kt | 60 +++++++++++++++++++ .../boot/SentryAutoConfigurationTest.kt | 60 +++++++++++++++++++ 2 files changed, 120 insertions(+) diff --git a/sentry-spring-boot-jakarta/src/test/kotlin/io/sentry/spring/boot/jakarta/SentryAutoConfigurationTest.kt b/sentry-spring-boot-jakarta/src/test/kotlin/io/sentry/spring/boot/jakarta/SentryAutoConfigurationTest.kt index 8e5221203f..4dd722c071 100644 --- a/sentry-spring-boot-jakarta/src/test/kotlin/io/sentry/spring/boot/jakarta/SentryAutoConfigurationTest.kt +++ b/sentry-spring-boot-jakarta/src/test/kotlin/io/sentry/spring/boot/jakarta/SentryAutoConfigurationTest.kt @@ -37,10 +37,15 @@ import org.mockito.kotlin.anyOrNull import org.mockito.kotlin.mock import org.mockito.kotlin.verify import org.mockito.kotlin.whenever +import org.quartz.JobExecutionContext +import org.quartz.JobExecutionException +import org.quartz.JobListener +import org.quartz.Scheduler import org.quartz.core.QuartzScheduler import org.slf4j.MDC import org.springframework.aop.support.NameMatchMethodPointcut import org.springframework.boot.autoconfigure.AutoConfigurations +import org.springframework.boot.autoconfigure.quartz.QuartzAutoConfiguration import org.springframework.boot.autoconfigure.quartz.SchedulerFactoryBeanCustomizer import org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration import org.springframework.boot.context.annotation.UserConfigurations @@ -782,6 +787,61 @@ class SentryAutoConfigurationTest { } } + @Test + fun `Sentry quartz job listener is added`() { + contextRunner.withPropertyValues("sentry.dsn=http://key@localhost/proj", "sentry.enable-automatic-checkins=true") + .withUserConfiguration(QuartzAutoConfiguration::class.java) + .run { + val jobListeners = it.getBean(Scheduler::class.java).listenerManager.jobListeners + assertThat(jobListeners).hasSize(1) + assertThat(jobListeners[0]).matches( + { it.name == "sentry-job-listener" }, + "is sentry job listener" + ) + } + } + + @Test + fun `user defined SchedulerFactoryBeanCustomizer overrides Sentry Customizer`() { + contextRunner.withPropertyValues("sentry.dsn=http://key@localhost/proj", "sentry.enable-automatic-checkins=true") + .withUserConfiguration(QuartzAutoConfiguration::class.java, CustomSchedulerFactoryBeanCustomizerConfiguration::class.java) + .run { + val jobListeners = it.getBean(Scheduler::class.java).listenerManager.jobListeners + assertThat(jobListeners).hasSize(1) + assertThat(jobListeners[0]).matches( + { it.name == "custom-job-listener" }, + "is custom job listener" + ) + } + } + + @Configuration(proxyBeanMethods = false) + open class CustomSchedulerFactoryBeanCustomizerConfiguration { + class MyJobListener : JobListener { + override fun getName() = "custom-job-listener" + + override fun jobToBeExecuted(context: JobExecutionContext?) { + // do nothing + } + + override fun jobExecutionVetoed(context: JobExecutionContext?) { + // do nothing + } + + override fun jobWasExecuted( + context: JobExecutionContext?, + jobException: JobExecutionException? + ) { + // do nothing + } + } + + @Bean + open fun mySchedulerFactoryBeanCustomizer(): SchedulerFactoryBeanCustomizer { + return SchedulerFactoryBeanCustomizer { schedulerFactoryBean -> schedulerFactoryBean.setGlobalJobListeners(MyJobListener()) } + } + } + @Configuration(proxyBeanMethods = false) open class CustomOptionsConfigurationConfiguration { diff --git a/sentry-spring-boot/src/test/kotlin/io/sentry/spring/boot/SentryAutoConfigurationTest.kt b/sentry-spring-boot/src/test/kotlin/io/sentry/spring/boot/SentryAutoConfigurationTest.kt index 71369d6f2d..14db6fc383 100644 --- a/sentry-spring-boot/src/test/kotlin/io/sentry/spring/boot/SentryAutoConfigurationTest.kt +++ b/sentry-spring-boot/src/test/kotlin/io/sentry/spring/boot/SentryAutoConfigurationTest.kt @@ -36,10 +36,15 @@ import org.mockito.kotlin.anyOrNull import org.mockito.kotlin.mock import org.mockito.kotlin.verify import org.mockito.kotlin.whenever +import org.quartz.JobExecutionContext +import org.quartz.JobExecutionException +import org.quartz.JobListener +import org.quartz.Scheduler import org.quartz.core.QuartzScheduler import org.slf4j.MDC import org.springframework.aop.support.NameMatchMethodPointcut import org.springframework.boot.autoconfigure.AutoConfigurations +import org.springframework.boot.autoconfigure.quartz.QuartzAutoConfiguration import org.springframework.boot.autoconfigure.quartz.SchedulerFactoryBeanCustomizer import org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration import org.springframework.boot.context.annotation.UserConfigurations @@ -782,6 +787,61 @@ class SentryAutoConfigurationTest { } } + @Test + fun `Sentry quartz job listener is added`() { + contextRunner.withPropertyValues("sentry.dsn=http://key@localhost/proj", "sentry.enable-automatic-checkins=true") + .withUserConfiguration(QuartzAutoConfiguration::class.java) + .run { + val jobListeners = it.getBean(Scheduler::class.java).listenerManager.jobListeners + assertThat(jobListeners).hasSize(1) + assertThat(jobListeners[0]).matches( + { it.name == "sentry-job-listener" }, + "is sentry job listener" + ) + } + } + + @Test + fun `user defined SchedulerFactoryBeanCustomizer overrides Sentry Customizer`() { + contextRunner.withPropertyValues("sentry.dsn=http://key@localhost/proj", "sentry.enable-automatic-checkins=true") + .withUserConfiguration(QuartzAutoConfiguration::class.java, CustomSchedulerFactoryBeanCustomizerConfiguration::class.java) + .run { + val jobListeners = it.getBean(Scheduler::class.java).listenerManager.jobListeners + assertThat(jobListeners).hasSize(1) + assertThat(jobListeners[0]).matches( + { it.name == "custom-job-listener" }, + "is custom job listener" + ) + } + } + + @Configuration(proxyBeanMethods = false) + open class CustomSchedulerFactoryBeanCustomizerConfiguration { + class MyJobListener : JobListener { + override fun getName() = "custom-job-listener" + + override fun jobToBeExecuted(context: JobExecutionContext?) { + // do nothing + } + + override fun jobExecutionVetoed(context: JobExecutionContext?) { + // do nothing + } + + override fun jobWasExecuted( + context: JobExecutionContext?, + jobException: JobExecutionException? + ) { + // do nothing + } + } + + @Bean + open fun mySchedulerFactoryBeanCustomizer(): SchedulerFactoryBeanCustomizer { + return SchedulerFactoryBeanCustomizer { schedulerFactoryBean -> schedulerFactoryBean.setGlobalJobListeners(MyJobListener()) } + } + } + @Configuration(proxyBeanMethods = false) open class CustomOptionsConfigurationConfiguration {