From b78f1e5be837f731f89648daf475b39b3cd62309 Mon Sep 17 00:00:00 2001 From: Diego Alonso Marquez Palacios Date: Fri, 24 Jan 2025 13:21:24 -0500 Subject: [PATCH 01/11] feat(pubsub)!: set max ack extension period to 60 minutes --- .../google/cloud/spring/pubsub/core/PubSubConfiguration.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-cloud-gcp-pubsub/src/main/java/com/google/cloud/spring/pubsub/core/PubSubConfiguration.java b/spring-cloud-gcp-pubsub/src/main/java/com/google/cloud/spring/pubsub/core/PubSubConfiguration.java index 4faec0f4c7..c0c0a0853e 100644 --- a/spring-cloud-gcp-pubsub/src/main/java/com/google/cloud/spring/pubsub/core/PubSubConfiguration.java +++ b/spring-cloud-gcp-pubsub/src/main/java/com/google/cloud/spring/pubsub/core/PubSubConfiguration.java @@ -37,7 +37,7 @@ public class PubSubConfiguration { /** Default number of executor threads. */ public static final int DEFAULT_EXECUTOR_THREADS = 4; - private static final Long DEFAULT_MAX_ACK_EXTENSION_PERIOD = 0L; + private static final Long DEFAULT_MAX_ACK_EXTENSION_PERIOD = 3600L; /** * Automatically extracted user-provided properties. Contains only short subscription keys From c4f0a4e5647af1ea77cdf3c3d881a37139756aaf Mon Sep 17 00:00:00 2001 From: Diego Alonso Marquez Palacios Date: Fri, 24 Jan 2025 13:30:26 -0500 Subject: [PATCH 02/11] update default max global threads to 5 --- .../google/cloud/spring/pubsub/core/PubSubConfiguration.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-cloud-gcp-pubsub/src/main/java/com/google/cloud/spring/pubsub/core/PubSubConfiguration.java b/spring-cloud-gcp-pubsub/src/main/java/com/google/cloud/spring/pubsub/core/PubSubConfiguration.java index c0c0a0853e..f9cf3513e3 100644 --- a/spring-cloud-gcp-pubsub/src/main/java/com/google/cloud/spring/pubsub/core/PubSubConfiguration.java +++ b/spring-cloud-gcp-pubsub/src/main/java/com/google/cloud/spring/pubsub/core/PubSubConfiguration.java @@ -35,7 +35,7 @@ public class PubSubConfiguration { private static final Logger logger = LoggerFactory.getLogger(PubSubConfiguration.class); /** Default number of executor threads. */ - public static final int DEFAULT_EXECUTOR_THREADS = 4; + public static final int DEFAULT_EXECUTOR_THREADS = 5; private static final Long DEFAULT_MAX_ACK_EXTENSION_PERIOD = 3600L; From 61331deb98ec9a47f9a97d028a3d2d3f70f99f85 Mon Sep 17 00:00:00 2001 From: Diego Alonso Marquez Palacios Date: Fri, 24 Jan 2025 13:30:32 -0500 Subject: [PATCH 03/11] update tests --- .../pubsub/GcpPubSubAutoConfigurationTests.java | 6 +++--- .../cloud/spring/pubsub/core/PubSubConfigurationTests.java | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/spring-cloud-gcp-autoconfigure/src/test/java/com/google/cloud/spring/autoconfigure/pubsub/GcpPubSubAutoConfigurationTests.java b/spring-cloud-gcp-autoconfigure/src/test/java/com/google/cloud/spring/autoconfigure/pubsub/GcpPubSubAutoConfigurationTests.java index 3c82a21772..da0f58e2d1 100644 --- a/spring-cloud-gcp-autoconfigure/src/test/java/com/google/cloud/spring/autoconfigure/pubsub/GcpPubSubAutoConfigurationTests.java +++ b/spring-cloud-gcp-autoconfigure/src/test/java/com/google/cloud/spring/autoconfigure/pubsub/GcpPubSubAutoConfigurationTests.java @@ -295,7 +295,7 @@ void threadPoolScheduler_noConfigurationSet_globalCreated() { ThreadPoolTaskScheduler globalSchedulerBean = (ThreadPoolTaskScheduler) ctx.getBean("globalPubSubSubscriberThreadPoolScheduler"); - assertThat(FieldUtils.readField(globalSchedulerBean, "poolSize", true)).isEqualTo(4); + assertThat(FieldUtils.readField(globalSchedulerBean, "poolSize", true)).isEqualTo(5); assertThat(globalSchedulerBean.getThreadNamePrefix()) .isEqualTo("global-gcp-pubsub-subscriber"); assertThat(globalSchedulerBean.isDaemon()).isTrue(); @@ -359,7 +359,7 @@ void threadPoolTaskScheduler_selectiveConfigurationSet() { assertThat(FieldUtils.readField(selectiveScheduler, "poolSize", true)).isEqualTo(7); assertThat(globalScheduler.getThreadNamePrefix()) .isEqualTo("global-gcp-pubsub-subscriber"); - assertThat(FieldUtils.readField(globalScheduler, "poolSize", true)).isEqualTo(4); + assertThat(FieldUtils.readField(globalScheduler, "poolSize", true)).isEqualTo(5); assertThat(globalScheduler.isDaemon()).isTrue(); }); } @@ -507,7 +507,7 @@ void pullConfig_defaultConfigurationSet() { assertThat( gcpPubSubProperties.computeMaxAckExtensionPeriod( "subscription-name", projectIdProvider.getProjectId())) - .isZero(); + .isEqualTo(3600); assertThat( gcpPubSubProperties.computeMinDurationPerAckExtension( "subscription-name", projectIdProvider.getProjectId())) diff --git a/spring-cloud-gcp-pubsub/src/test/java/com/google/cloud/spring/pubsub/core/PubSubConfigurationTests.java b/spring-cloud-gcp-pubsub/src/test/java/com/google/cloud/spring/pubsub/core/PubSubConfigurationTests.java index 0caffb8598..f1c6e4f43f 100644 --- a/spring-cloud-gcp-pubsub/src/test/java/com/google/cloud/spring/pubsub/core/PubSubConfigurationTests.java +++ b/spring-cloud-gcp-pubsub/src/test/java/com/google/cloud/spring/pubsub/core/PubSubConfigurationTests.java @@ -265,7 +265,7 @@ void testComputeMaxAckExtensionPeriod_returnDefault() { Long result = pubSubConfiguration.computeMaxAckExtensionPeriod("subscription-name", "projectId"); - assertThat(result).isZero(); + assertThat(result).isEqualTo(3600L); } @Test From e97e0abd02680994c02eb85618ed24daa21b960f Mon Sep 17 00:00:00 2001 From: Diego Alonso Marquez Palacios Date: Fri, 24 Jan 2025 13:58:32 -0500 Subject: [PATCH 04/11] update tests ii --- .../spring/pubsub/support/DefaultSubscriberFactoryTests.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-cloud-gcp-pubsub/src/test/java/com/google/cloud/spring/pubsub/support/DefaultSubscriberFactoryTests.java b/spring-cloud-gcp-pubsub/src/test/java/com/google/cloud/spring/pubsub/support/DefaultSubscriberFactoryTests.java index f3d41e2d74..5441fdb335 100644 --- a/spring-cloud-gcp-pubsub/src/test/java/com/google/cloud/spring/pubsub/support/DefaultSubscriberFactoryTests.java +++ b/spring-cloud-gcp-pubsub/src/test/java/com/google/cloud/spring/pubsub/support/DefaultSubscriberFactoryTests.java @@ -534,7 +534,7 @@ void testGetMaxAckExtensionPeriod_newConfiguration() { new DefaultSubscriberFactory(projectIdProvider, this.pubSubConfig); assertThat(factory.getMaxAckExtensionPeriod("subscription-name")) - .isEqualTo(Duration.ofSeconds(0L)); + .isEqualTo(Duration.ofSeconds(3600L)); } @Test From 41f2a477b703d775248e5233b90d271de2d964b3 Mon Sep 17 00:00:00 2001 From: Diego Alonso Marquez Palacios Date: Wed, 29 Jan 2025 22:20:32 -0500 Subject: [PATCH 05/11] use defaults from client library this removes the global executor configuration since it relied on a hardcoded default value --- .../pubsub/GcpPubSubAutoConfiguration.java | 45 +- .../GcpPubSubAutoConfigurationTests.java | 590 ++++++++---------- ...bSubAutoConfigurationIntegrationTests.java | 99 +-- .../pubsub/core/PubSubConfiguration.java | 10 +- .../support/DefaultSubscriberFactory.java | 30 +- .../pubsub/core/PubSubConfigurationTests.java | 2 +- .../DefaultSubscriberFactoryTests.java | 19 +- 7 files changed, 371 insertions(+), 424 deletions(-) diff --git a/spring-cloud-gcp-autoconfigure/src/main/java/com/google/cloud/spring/autoconfigure/pubsub/GcpPubSubAutoConfiguration.java b/spring-cloud-gcp-autoconfigure/src/main/java/com/google/cloud/spring/autoconfigure/pubsub/GcpPubSubAutoConfiguration.java index d8c3d30162..73ee2a2716 100644 --- a/spring-cloud-gcp-autoconfigure/src/main/java/com/google/cloud/spring/autoconfigure/pubsub/GcpPubSubAutoConfiguration.java +++ b/spring-cloud-gcp-autoconfigure/src/main/java/com/google/cloud/spring/autoconfigure/pubsub/GcpPubSubAutoConfiguration.java @@ -111,14 +111,10 @@ public class GcpPubSubAutoConfiguration { private final ApplicationContext applicationContext; - private ThreadPoolTaskScheduler globalScheduler; - private FlowControlSettings globalFlowControlSettings; private RetrySettings globalRetrySettings; - private ExecutorProvider globalExecutorProvider; - private ObjectProvider selectiveSchedulerThreadNameProvider; public GcpPubSubAutoConfiguration( @@ -257,7 +253,6 @@ public SubscriberFactory defaultSubscriberFactory( factory.setExecutorProvider(executorProvider.get()); } factory.setExecutorProviderMap(this.executorProviderMap); - factory.setGlobalExecutorProvider(this.globalExecutorProvider); factory.setCredentialsProvider(this.finalCredentialsProvider); factory.setHeaderProvider(this.headerProvider); @@ -375,8 +370,8 @@ public PublisherFactory defaultPublisherFactory( factory.setEndpoint(gcpPubSubProperties.getPublisher().getEndpoint()); factory.setUniverseDomain(gcpPubSubProperties.getPublisher().getUniverseDomain()); - List customizers = customizersProvider.orderedStream() - .collect(Collectors.toList()); + List customizers = + customizersProvider.orderedStream().collect(Collectors.toList()); Collections.reverse(customizers); // highest priority customizer needs to be last factory.setCustomizers(customizers); @@ -438,7 +433,8 @@ public SubscriptionAdminClient subscriptionAdminClient( public TransportChannelProvider subscriberTransportChannelProvider() { return SubscriberStubSettings.defaultGrpcTransportProviderBuilder() // default value specified by pubsub client library, - // see https://github.com/googleapis/java-pubsub/blob/main/google-cloud-pubsub/src/main/java/com/google/cloud/pubsub/v1/Subscriber.java#L487. + // see + // https://github.com/googleapis/java-pubsub/blob/main/google-cloud-pubsub/src/main/java/com/google/cloud/pubsub/v1/Subscriber.java#L487. .setMaxInboundMetadataSize(4 * 1024 * 1024) .setKeepAliveTime( Duration.ofMinutes(this.gcpPubSubProperties.getKeepAliveIntervalMinutes())) @@ -464,13 +460,6 @@ public void registerSubscriberSettings() { } private void registerSubscriberThreadPoolSchedulerBeans(GenericApplicationContext context) { - Integer numThreads = getGlobalExecutorThreads(); - this.globalScheduler = - createAndRegisterSchedulerBean( - numThreads, - "global-gcp-pubsub-subscriber", - "globalPubSubSubscriberThreadPoolScheduler", - context); registerSelectiveSchedulerBeans(context); } @@ -494,11 +483,6 @@ private void registerExecutorProviderBeans(GenericApplicationContext context) { if (context.containsBean("subscriberExecutorProvider")) { return; } - if (this.globalScheduler != null) { - this.globalExecutorProvider = - createAndRegisterExecutorProvider( - "globalSubscriberExecutorProvider", this.globalScheduler, context); - } createAndRegisterSelectiveExecutorProvider(context); } @@ -533,10 +517,12 @@ private void registerSelectiveSchedulerBeans(GenericApplicationContext context) Integer selectiveExecutorThreads = selectiveSubscriber.getExecutorThreads(); if (selectiveExecutorThreads != null) { String qualifiedName = fullSubscriptionName.toString(); // will include slashes - String threadName = selectiveSchedulerThreadNameProvider - .getIfAvailable( - () -> subscriptionName -> "gcp-pubsub-subscriber-" + subscriptionName.toString()) - .getThreadName(fullSubscriptionName); + String threadName = + selectiveSchedulerThreadNameProvider + .getIfAvailable( + () -> + subscriptionName -> "gcp-pubsub-subscriber-" + subscriptionName.toString()) + .getThreadName(fullSubscriptionName); String beanName = "threadPoolScheduler_" + qualifiedName; ThreadPoolTaskScheduler selectiveScheduler = createAndRegisterSchedulerBean(selectiveExecutorThreads, threadName, beanName, context); @@ -559,7 +545,9 @@ private ThreadPoolTaskScheduler createAndRegisterSchedulerBean( String threadName, String beanName, GenericApplicationContext context) { - ThreadPoolTaskScheduler scheduler = createThreadPoolTaskScheduler(executorThreads, threadName); + ThreadPoolTaskScheduler scheduler; + scheduler = + executorThreads == null ? null : createThreadPoolTaskScheduler(executorThreads, threadName); context.registerBeanDefinition( beanName, BeanDefinitionBuilder.genericBeanDefinition(ThreadPoolTaskScheduler.class, () -> scheduler) @@ -618,9 +606,7 @@ private void createAndRegisterSelectiveExecutorProvider(GenericApplicationContex ThreadPoolTaskScheduler scheduler = schedulerSet.getValue(); ExecutorProvider executorProvider = createAndRegisterExecutorProvider( - "subscriberExecutorProvider-" + qualifiedName, - scheduler, - context); + "subscriberExecutorProvider-" + qualifiedName, scheduler, context); this.executorProviderMap.putIfAbsent(fullSubscriptionName, executorProvider); } } @@ -660,7 +646,6 @@ private void createAndRegisterSelectiveRetrySettings(GenericApplicationContext c } private Integer getGlobalExecutorThreads() { - Integer numThreads = this.gcpPubSubProperties.getSubscriber().getExecutorThreads(); - return numThreads != null ? numThreads : PubSubConfiguration.DEFAULT_EXECUTOR_THREADS; + return this.gcpPubSubProperties.getSubscriber().getExecutorThreads(); } } diff --git a/spring-cloud-gcp-autoconfigure/src/test/java/com/google/cloud/spring/autoconfigure/pubsub/GcpPubSubAutoConfigurationTests.java b/spring-cloud-gcp-autoconfigure/src/test/java/com/google/cloud/spring/autoconfigure/pubsub/GcpPubSubAutoConfigurationTests.java index da0f58e2d1..cd6396d8f0 100644 --- a/spring-cloud-gcp-autoconfigure/src/test/java/com/google/cloud/spring/autoconfigure/pubsub/GcpPubSubAutoConfigurationTests.java +++ b/spring-cloud-gcp-autoconfigure/src/test/java/com/google/cloud/spring/autoconfigure/pubsub/GcpPubSubAutoConfigurationTests.java @@ -25,6 +25,7 @@ import com.google.api.gax.batching.FlowController; import com.google.api.gax.core.CredentialsProvider; import com.google.api.gax.core.ExecutorProvider; +import com.google.api.gax.core.InstantiatingExecutorProvider; import com.google.api.gax.grpc.InstantiatingGrpcChannelProvider; import com.google.api.gax.retrying.RetrySettings; import com.google.api.gax.rpc.StatusCode.Code; @@ -57,23 +58,21 @@ import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; import org.threeten.bp.Duration; -/** - * Tests for Pub/Sub autoconfiguration. - */ +/** Tests for Pub/Sub autoconfiguration. */ @ExtendWith(OutputCaptureExtension.class) class GcpPubSubAutoConfigurationTests { private ApplicationContextRunner contextRunner; - static final BatchingSettings TEST_BATCHING_SETTINGS = BatchingSettings.newBuilder() - .setDelayThreshold(Duration.ofSeconds(11)) - .build(); + static final BatchingSettings TEST_BATCHING_SETTINGS = + BatchingSettings.newBuilder().setDelayThreshold(Duration.ofSeconds(11)).build(); @BeforeEach void init() { - contextRunner = new ApplicationContextRunner() - .withConfiguration(AutoConfigurations.of(GcpPubSubAutoConfiguration.class)) - .withUserConfiguration(TestConfig.class); + contextRunner = + new ApplicationContextRunner() + .withConfiguration(AutoConfigurations.of(GcpPubSubAutoConfiguration.class)) + .withUserConfiguration(TestConfig.class); } @Test @@ -88,17 +87,18 @@ void keepAliveValue_default() { TransportChannelProvider publisherTcp = ctx.getBean("publisherTransportChannelProvider", TransportChannelProvider.class); assertThat( - ((InstantiatingGrpcChannelProvider) subscriberTcp).getKeepAliveTime().toMinutes()) + ((InstantiatingGrpcChannelProvider) subscriberTcp).getKeepAliveTime().toMinutes()) .isEqualTo(5); assertThat( - ((InstantiatingGrpcChannelProvider) publisherTcp).getKeepAliveTime().toMinutes()) + ((InstantiatingGrpcChannelProvider) publisherTcp).getKeepAliveTime().toMinutes()) .isEqualTo(5); }); } @Test void keepAliveValue_custom() { - contextRunner.withPropertyValues("spring.cloud.gcp.pubsub.keepAliveIntervalMinutes=2") + contextRunner + .withPropertyValues("spring.cloud.gcp.pubsub.keepAliveIntervalMinutes=2") .run( ctx -> { GcpPubSubProperties props = ctx.getBean(GcpPubSubProperties.class); @@ -109,10 +109,14 @@ void keepAliveValue_custom() { TransportChannelProvider publisherTcp = ctx.getBean("publisherTransportChannelProvider", TransportChannelProvider.class); assertThat( - ((InstantiatingGrpcChannelProvider) subscriberTcp).getKeepAliveTime().toMinutes()) + ((InstantiatingGrpcChannelProvider) subscriberTcp) + .getKeepAliveTime() + .toMinutes()) .isEqualTo(2); assertThat( - ((InstantiatingGrpcChannelProvider) publisherTcp).getKeepAliveTime().toMinutes()) + ((InstantiatingGrpcChannelProvider) publisherTcp) + .getKeepAliveTime() + .toMinutes()) .isEqualTo(2); }); } @@ -144,6 +148,25 @@ void maxInboundMetadataSize_default() { }); } + @Test + void defaultSubscriberFactory_noExecutorThreadsSet_usesClientDefault() { + contextRunner.run( + ctx -> { + DefaultSubscriberFactory defaultSubscriberFactory = + ctx.getBean("defaultSubscriberFactory", DefaultSubscriberFactory.class); + Subscriber subscriber = + defaultSubscriberFactory.createSubscriber("dead10cc", (message, consumer) -> {}); + // we confirm that the created subscriber uses the default thread setting in the client (5 + // as of Jan 2025). + InstantiatingExecutorProvider executorProvider = + (InstantiatingExecutorProvider) + FieldUtils.readField(subscriber, "executorProvider", true); + Integer threadsPerChannel = + (Integer) FieldUtils.readField(subscriber, "THREADS_PER_CHANNEL", true); + assertThat(executorProvider.getExecutorThreadCount()).isEqualTo(threadsPerChannel); + }); + } + @Test void retryableCodes_default() { contextRunner.run( @@ -167,13 +190,13 @@ void retryableCodes_empty() { DefaultSubscriberFactory defaultSubscriberFactory = ctx.getBean("defaultSubscriberFactory", DefaultSubscriberFactory.class); - assertThat(properties.getSubscriber().getRetryableCodes()).isEqualTo(new Code[]{}); + assertThat(properties.getSubscriber().getRetryableCodes()).isEqualTo(new Code[] {}); assertThat( - properties.computeRetryableCodes( - "subscription-name", projectIdProvider.getProjectId())) - .isEqualTo(new Code[]{}); + properties.computeRetryableCodes( + "subscription-name", projectIdProvider.getProjectId())) + .isEqualTo(new Code[] {}); assertThat(defaultSubscriberFactory.getRetryableCodes("subscription-name")) - .isEqualTo(new Code[]{}); + .isEqualTo(new Code[] {}); }); } @@ -189,13 +212,13 @@ void retryableCodes_Internal() { ctx.getBean("defaultSubscriberFactory", DefaultSubscriberFactory.class); assertThat(properties.getSubscriber().getRetryableCodes()) - .isEqualTo(new Code[]{Code.INTERNAL}); + .isEqualTo(new Code[] {Code.INTERNAL}); assertThat( - properties.computeRetryableCodes( - "subscription-name", projectIdProvider.getProjectId())) - .isEqualTo(new Code[]{Code.INTERNAL}); + properties.computeRetryableCodes( + "subscription-name", projectIdProvider.getProjectId())) + .isEqualTo(new Code[] {Code.INTERNAL}); assertThat(defaultSubscriberFactory.getRetryableCodes("subscription-name")) - .isEqualTo(new Code[]{Code.INTERNAL}); + .isEqualTo(new Code[] {Code.INTERNAL}); }); } @@ -211,13 +234,13 @@ void retryableCodes_many() { DefaultSubscriberFactory defaultSubscriberFactory = ctx.getBean("defaultSubscriberFactory", DefaultSubscriberFactory.class); Code[] expectedRetryableCodes = - new Code[]{Code.UNKNOWN, Code.ABORTED, Code.UNAVAILABLE, Code.INTERNAL}; + new Code[] {Code.UNKNOWN, Code.ABORTED, Code.UNAVAILABLE, Code.INTERNAL}; assertThat(properties.getSubscriber().getRetryableCodes()) .isEqualTo(expectedRetryableCodes); assertThat( - properties.computeRetryableCodes( - "subscription-name", projectIdProvider.getProjectId())) + properties.computeRetryableCodes( + "subscription-name", projectIdProvider.getProjectId())) .isEqualTo(expectedRetryableCodes); assertThat(defaultSubscriberFactory.getRetryableCodes("subscription-name")) .isEqualTo(expectedRetryableCodes); @@ -235,7 +258,7 @@ void retryableCodes_selectiveConfigurationSet() { ctx.getBean("defaultSubscriberFactory", DefaultSubscriberFactory.class); assertThat(defaultSubscriberFactory.getRetryableCodes("subscription-name")) .isEqualTo( - new Code[]{Code.UNKNOWN, Code.ABORTED, Code.UNAVAILABLE, Code.INTERNAL}); + new Code[] {Code.UNKNOWN, Code.ABORTED, Code.UNAVAILABLE, Code.INTERNAL}); assertThat(defaultSubscriberFactory.getRetryableCodes("other")).isNull(); }); } @@ -251,9 +274,9 @@ void retryableCodes_globalAndSelectiveConfigurationSet_selectiveTakesPrecedence( DefaultSubscriberFactory defaultSubscriberFactory = ctx.getBean("defaultSubscriberFactory", DefaultSubscriberFactory.class); assertThat(defaultSubscriberFactory.getRetryableCodes("subscription-name")) - .isEqualTo(new Code[]{Code.UNKNOWN, Code.ABORTED, Code.UNAVAILABLE}); + .isEqualTo(new Code[] {Code.UNKNOWN, Code.ABORTED, Code.UNAVAILABLE}); assertThat(defaultSubscriberFactory.getRetryableCodes("other")) - .isEqualTo(new Code[]{Code.INTERNAL}); + .isEqualTo(new Code[] {Code.INTERNAL}); }); } @@ -268,7 +291,7 @@ void retryableCodes_globalAndDifferentSelectiveConfigurationSet_pickGlobal() { DefaultSubscriberFactory defaultSubscriberFactory = ctx.getBean("defaultSubscriberFactory", DefaultSubscriberFactory.class); assertThat(defaultSubscriberFactory.getRetryableCodes("subscription-name")) - .isEqualTo(new Code[]{Code.INTERNAL}); + .isEqualTo(new Code[] {Code.INTERNAL}); }); } @@ -283,25 +306,10 @@ void customExecutorProviderUsedWhenProvided() { DefaultSubscriberFactory factory = ctx.getBean("defaultSubscriberFactory", DefaultSubscriberFactory.class); assertThat(factory.getExecutorProvider("name")).isSameAs(executorProvider); - assertThat(ctx.containsBean("globalSubscriberExecutorProvider")).isFalse(); assertThat(ctx.containsBean("subscriberExecutorProvider-name")).isFalse(); }); } - @Test - void threadPoolScheduler_noConfigurationSet_globalCreated() { - contextRunner.run( - ctx -> { - ThreadPoolTaskScheduler globalSchedulerBean = - (ThreadPoolTaskScheduler) ctx.getBean("globalPubSubSubscriberThreadPoolScheduler"); - - assertThat(FieldUtils.readField(globalSchedulerBean, "poolSize", true)).isEqualTo(5); - assertThat(globalSchedulerBean.getThreadNamePrefix()) - .isEqualTo("global-gcp-pubsub-subscriber"); - assertThat(globalSchedulerBean.isDaemon()).isTrue(); - }); - } - @Test void subscriberThreadPoolTaskScheduler_globalConfigurationSet() { contextRunner @@ -309,31 +317,7 @@ void subscriberThreadPoolTaskScheduler_globalConfigurationSet() { .run( ctx -> { GcpPubSubProperties gcpPubSubProperties = ctx.getBean(GcpPubSubProperties.class); - ThreadPoolTaskScheduler globalSchedulerBean = - (ThreadPoolTaskScheduler) ctx.getBean( - "globalPubSubSubscriberThreadPoolScheduler"); - assertThat(gcpPubSubProperties.getSubscriber().getExecutorThreads()).isEqualTo(7); - assertThat(globalSchedulerBean.getThreadNamePrefix()) - .isEqualTo("global-gcp-pubsub-subscriber"); - assertThat(FieldUtils.readField(globalSchedulerBean, "poolSize", true)).isEqualTo(7); - assertThat(globalSchedulerBean.isDaemon()).isTrue(); - }); - } - - @Test - void subscriberExecutorProvider_globalConfigurationSet() { - contextRunner - .withPropertyValues("spring.cloud.gcp.pubsub.subscriber.executor-threads=7") - .run( - ctx -> { - DefaultSubscriberFactory factory = - (DefaultSubscriberFactory) ctx.getBean("defaultSubscriberFactory"); - ExecutorProvider globalExecutorProvider = - (ExecutorProvider) ctx.getBean("globalSubscriberExecutorProvider"); - - assertThat(globalExecutorProvider).isNotNull(); - assertThat(factory.getExecutorProvider("other")).isSameAs(globalExecutorProvider); }); } @@ -347,20 +331,14 @@ void threadPoolTaskScheduler_selectiveConfigurationSet() { // Verify that selective and global beans have been created ThreadPoolTaskScheduler selectiveScheduler = - (ThreadPoolTaskScheduler) ctx.getBean( - "threadPoolScheduler_projects/fake project/subscriptions/subscription-name"); - ThreadPoolTaskScheduler globalScheduler = - (ThreadPoolTaskScheduler) ctx.getBean( - "globalPubSubSubscriberThreadPoolScheduler"); + (ThreadPoolTaskScheduler) + ctx.getBean( + "threadPoolScheduler_projects/fake project/subscriptions/subscription-name"); assertThat(selectiveScheduler.getThreadNamePrefix()) .isEqualTo( "gcp-pubsub-subscriber-projects/fake project/subscriptions/subscription-name"); assertThat(selectiveScheduler.isDaemon()).isTrue(); assertThat(FieldUtils.readField(selectiveScheduler, "poolSize", true)).isEqualTo(7); - assertThat(globalScheduler.getThreadNamePrefix()) - .isEqualTo("global-gcp-pubsub-subscriber"); - assertThat(FieldUtils.readField(globalScheduler, "poolSize", true)).isEqualTo(5); - assertThat(globalScheduler.isDaemon()).isTrue(); }); } @@ -369,15 +347,17 @@ void threadPoolTaskScheduler_selectiveThreadNameConfiguration() { contextRunner .withPropertyValues( "spring.cloud.gcp.pubsub.subscription.subscription-name.executor-threads=7") - .withBean(SelectiveSchedulerThreadNameProvider.class, + .withBean( + SelectiveSchedulerThreadNameProvider.class, () -> subscriptionName -> "custom-" + subscriptionName.getSubscription()) .run( ctx -> { ThreadPoolTaskScheduler selectiveScheduler = - (ThreadPoolTaskScheduler) ctx.getBean( - "threadPoolScheduler_projects/fake project/subscriptions/subscription-name"); - assertThat(selectiveScheduler.getThreadNamePrefix()).isEqualTo( - "custom-subscription-name"); + (ThreadPoolTaskScheduler) + ctx.getBean( + "threadPoolScheduler_projects/fake project/subscriptions/subscription-name"); + assertThat(selectiveScheduler.getThreadNamePrefix()) + .isEqualTo("custom-subscription-name"); }); } @@ -391,12 +371,9 @@ void subscriberExecutorProvider_selectiveConfigurationSet() { DefaultSubscriberFactory factory = (DefaultSubscriberFactory) ctx.getBean("defaultSubscriberFactory"); ExecutorProvider selectiveExecutorProvider = - (ExecutorProvider) ctx.getBean( - "subscriberExecutorProvider-projects/fake project/subscriptions/subscription-name"); - ExecutorProvider globalExecutorProvider = - (ExecutorProvider) ctx.getBean("globalSubscriberExecutorProvider"); - - assertThat(globalExecutorProvider).isNotNull(); + (ExecutorProvider) + ctx.getBean( + "subscriberExecutorProvider-projects/fake project/subscriptions/subscription-name"); assertThat(selectiveExecutorProvider).isNotNull(); assertThat(factory.getExecutorProvider("subscription-name")) .isSameAs(selectiveExecutorProvider); @@ -411,45 +388,16 @@ void threadPoolScheduler_globalAndSelectiveConfigurationSet() { "spring.cloud.gcp.pubsub.subscription.subscription-name.executor-threads=3") .run( ctx -> { - // Verify that selective and global beans have been created ThreadPoolTaskScheduler selectiveScheduler = - (ThreadPoolTaskScheduler) ctx.getBean( - "threadPoolScheduler_projects/fake project/subscriptions/subscription-name"); - ThreadPoolTaskScheduler globalScheduler = - (ThreadPoolTaskScheduler) ctx.getBean( - "globalPubSubSubscriberThreadPoolScheduler"); + (ThreadPoolTaskScheduler) + ctx.getBean( + "threadPoolScheduler_projects/fake project/subscriptions/subscription-name"); assertThat(selectiveScheduler.getThreadNamePrefix()) .isEqualTo( "gcp-pubsub-subscriber-projects/fake project/subscriptions/subscription-name"); assertThat(FieldUtils.readField(selectiveScheduler, "poolSize", true)).isEqualTo(3); assertThat(selectiveScheduler.isDaemon()).isTrue(); - assertThat(globalScheduler.getThreadNamePrefix()) - .isEqualTo("global-gcp-pubsub-subscriber"); - assertThat(FieldUtils.readField(globalScheduler, "poolSize", true)).isEqualTo(5); - assertThat(globalScheduler.isDaemon()).isTrue(); - }); - } - - @Test - void threadPoolTaskScheduler_globalAndDifferentSelectiveConfigurationSet_onlyGlobalCreated() { - contextRunner - .withPropertyValues( - "spring.cloud.gcp.pubsub.subscriber.executor-threads=5", - "spring.cloud.gcp.pubsub.subscription.subscription-name.parallel-pull-count=3") - .run( - ctx -> { - - // Verify that only global thread pool task scheduler is created - ThreadPoolTaskScheduler globalScheduler = - (ThreadPoolTaskScheduler) ctx.getBean( - "globalPubSubSubscriberThreadPoolScheduler"); - - assertThat(globalScheduler.getThreadNamePrefix()) - .isEqualTo("global-gcp-pubsub-subscriber"); - assertThat(globalScheduler.isDaemon()).isTrue(); - assertThat(FieldUtils.readField(globalScheduler, "poolSize", true)).isEqualTo(5); - assertThat(ctx.containsBean("threadPoolScheduler_subscription-name")).isFalse(); }); } @@ -461,15 +409,8 @@ void subscriberExecutorProvider_globalAndDifferentSelectiveConfigurationSet_only "spring.cloud.gcp.pubsub.subscription.subscription-name.parallel-pull-count=3") .run( ctx -> { - DefaultSubscriberFactory factory = - (DefaultSubscriberFactory) ctx.getBean("defaultSubscriberFactory"); - - // Verify that global executor provider is created and used - ExecutorProvider globalExecutorProvider = - (ExecutorProvider) ctx.getBean("globalSubscriberExecutorProvider"); - assertThat( - ctx.containsBean("subscriberExecutorProvider-subscription-name")).isFalse(); - assertThat(factory.getGlobalExecutorProvider()).isSameAs(globalExecutorProvider); + assertThat(ctx.containsBean("subscriberExecutorProvider-subscription-name")) + .isFalse(); }); } @@ -484,14 +425,10 @@ void subscriberExecutorProvider_globalAndSelectiveConfigurationSet_selectiveTake DefaultSubscriberFactory factory = (DefaultSubscriberFactory) ctx.getBean("defaultSubscriberFactory"); ExecutorProvider selectiveExecutorProvider = - (ExecutorProvider) ctx.getBean( - "subscriberExecutorProvider-projects/fake project/subscriptions/subscription-name"); - ExecutorProvider globalExecutorProvider = - (ExecutorProvider) ctx.getBean("globalSubscriberExecutorProvider"); - + (ExecutorProvider) + ctx.getBean( + "subscriberExecutorProvider-projects/fake project/subscriptions/subscription-name"); assertThat(selectiveExecutorProvider).isNotNull(); - assertThat(globalExecutorProvider).isNotNull(); - assertThat(factory.getGlobalExecutorProvider()).isNotNull(); assertThat(factory.getExecutorProvider("subscription-name")) .isSameAs(selectiveExecutorProvider); }); @@ -499,32 +436,31 @@ void subscriberExecutorProvider_globalAndSelectiveConfigurationSet_selectiveTake @Test void pullConfig_defaultConfigurationSet() { - contextRunner - .run( - ctx -> { - GcpPubSubProperties gcpPubSubProperties = ctx.getBean(GcpPubSubProperties.class); - GcpProjectIdProvider projectIdProvider = ctx.getBean(GcpProjectIdProvider.class); - assertThat( + contextRunner.run( + ctx -> { + GcpPubSubProperties gcpPubSubProperties = ctx.getBean(GcpPubSubProperties.class); + GcpProjectIdProvider projectIdProvider = ctx.getBean(GcpProjectIdProvider.class); + assertThat( gcpPubSubProperties.computeMaxAckExtensionPeriod( "subscription-name", projectIdProvider.getProjectId())) - .isEqualTo(3600); - assertThat( + .isNull(); + assertThat( gcpPubSubProperties.computeMinDurationPerAckExtension( "subscription-name", projectIdProvider.getProjectId())) - .isNull(); - assertThat( + .isNull(); + assertThat( gcpPubSubProperties.computeMaxDurationPerAckExtension( "subscription-name", projectIdProvider.getProjectId())) - .isNull(); - assertThat( + .isNull(); + assertThat( gcpPubSubProperties.computeParallelPullCount( "subscription-name", projectIdProvider.getProjectId())) - .isNull(); - assertThat( + .isNull(); + assertThat( gcpPubSubProperties.computePullEndpoint( "subscription-name", projectIdProvider.getProjectId())) - .isNull(); - }); + .isNull(); + }); } @Test @@ -537,11 +473,9 @@ void minOrMaxDurationPerAckExtension_invalidSubscriberConfigurationSet() { ctx -> { DefaultSubscriberFactory factory = (DefaultSubscriberFactory) ctx.getBean("defaultSubscriberFactory"); - assertThatThrownBy(() -> - factory.createSubscriber( - "subscription-name", - (message, consumer) -> { - })) + assertThatThrownBy( + () -> + factory.createSubscriber("subscription-name", (message, consumer) -> {})) .isExactlyInstanceOf(IllegalArgumentException.class); }); } @@ -558,11 +492,9 @@ void minOrMaxDurationPerAckExtension_invalidSubscriptionConfigurationSet() { ctx -> { DefaultSubscriberFactory factory = (DefaultSubscriberFactory) ctx.getBean("defaultSubscriberFactory"); - assertThatThrownBy(() -> - factory.createSubscriber( - "subscription-name", - (message, consumer) -> { - })) + assertThatThrownBy( + () -> + factory.createSubscriber("subscription-name", (message, consumer) -> {})) .isExactlyInstanceOf(IllegalArgumentException.class); }); } @@ -581,27 +513,27 @@ void pullConfig_globalConfigurationSet() { GcpPubSubProperties gcpPubSubProperties = ctx.getBean(GcpPubSubProperties.class); GcpProjectIdProvider projectIdProvider = ctx.getBean(GcpProjectIdProvider.class); assertThat( - gcpPubSubProperties.computeMaxAckExtensionPeriod( - "subscription-name", projectIdProvider.getProjectId())) + gcpPubSubProperties.computeMaxAckExtensionPeriod( + "subscription-name", projectIdProvider.getProjectId())) .isEqualTo(7L); assertThat( - gcpPubSubProperties.computeMinDurationPerAckExtension( - "subscription-name", projectIdProvider.getProjectId())) + gcpPubSubProperties.computeMinDurationPerAckExtension( + "subscription-name", projectIdProvider.getProjectId())) .isEqualTo(3L); assertThat( - gcpPubSubProperties.computeMaxDurationPerAckExtension( - "subscription-name", projectIdProvider.getProjectId())) + gcpPubSubProperties.computeMaxDurationPerAckExtension( + "subscription-name", projectIdProvider.getProjectId())) .isEqualTo(4L); assertThat( - gcpPubSubProperties.computeParallelPullCount( - "subscription-name", projectIdProvider.getProjectId())) + gcpPubSubProperties.computeParallelPullCount( + "subscription-name", projectIdProvider.getProjectId())) .isEqualTo(12); assertThat( - gcpPubSubProperties.computePullEndpoint( - "subscription-name", projectIdProvider.getProjectId())) + gcpPubSubProperties.computePullEndpoint( + "subscription-name", projectIdProvider.getProjectId())) .isEqualTo("my-endpoint"); - assertThat(gcpPubSubProperties.getSubscriber().getMaxAckExtensionPeriod()).isEqualTo( - 7L); + assertThat(gcpPubSubProperties.getSubscriber().getMaxAckExtensionPeriod()) + .isEqualTo(7L); assertThat(gcpPubSubProperties.getSubscriber().getParallelPullCount()).isEqualTo(12); assertThat(gcpPubSubProperties.getSubscriber().getPullEndpoint()) .isEqualTo("my-endpoint"); @@ -622,28 +554,29 @@ void pullConfig_selectiveConfigurationSet() { GcpPubSubProperties gcpPubSubProperties = ctx.getBean(GcpPubSubProperties.class); GcpProjectIdProvider projectIdProvider = ctx.getBean(GcpProjectIdProvider.class); assertThat( - gcpPubSubProperties.computeMaxAckExtensionPeriod( - "subscription-name", projectIdProvider.getProjectId())) + gcpPubSubProperties.computeMaxAckExtensionPeriod( + "subscription-name", projectIdProvider.getProjectId())) .isEqualTo(7L); assertThat( - gcpPubSubProperties.computeMinDurationPerAckExtension( - "subscription-name", projectIdProvider.getProjectId())) + gcpPubSubProperties.computeMinDurationPerAckExtension( + "subscription-name", projectIdProvider.getProjectId())) .isEqualTo(3L); assertThat( - gcpPubSubProperties.computeMaxDurationPerAckExtension( - "subscription-name", projectIdProvider.getProjectId())) + gcpPubSubProperties.computeMaxDurationPerAckExtension( + "subscription-name", projectIdProvider.getProjectId())) .isEqualTo(4L); assertThat( - gcpPubSubProperties.computeParallelPullCount( - "subscription-name", projectIdProvider.getProjectId())) + gcpPubSubProperties.computeParallelPullCount( + "subscription-name", projectIdProvider.getProjectId())) .isEqualTo(12); assertThat( - gcpPubSubProperties.computePullEndpoint( - "subscription-name", projectIdProvider.getProjectId())) + gcpPubSubProperties.computePullEndpoint( + "subscription-name", projectIdProvider.getProjectId())) .isEqualTo("my-endpoint"); assertThat(gcpPubSubProperties.getFullyQualifiedSubscriberProperties()) - .containsKey(ProjectSubscriptionName.parse( - "projects/fake project/subscriptions/subscription-name")); + .containsKey( + ProjectSubscriptionName.parse( + "projects/fake project/subscriptions/subscription-name")); }); } @@ -666,50 +599,51 @@ void pullConfig_globalAndSelectiveConfigurationSet_selectiveTakesPrecedence() { GcpPubSubProperties gcpPubSubProperties = ctx.getBean(GcpPubSubProperties.class); GcpProjectIdProvider projectIdProvider = ctx.getBean(GcpProjectIdProvider.class); assertThat( - gcpPubSubProperties.computeMaxAckExtensionPeriod( - "subscription-name", projectIdProvider.getProjectId())) + gcpPubSubProperties.computeMaxAckExtensionPeriod( + "subscription-name", projectIdProvider.getProjectId())) .isEqualTo(7L); assertThat( - gcpPubSubProperties.computeMinDurationPerAckExtension( - "subscription-name", projectIdProvider.getProjectId())) + gcpPubSubProperties.computeMinDurationPerAckExtension( + "subscription-name", projectIdProvider.getProjectId())) .isEqualTo(5L); assertThat( - gcpPubSubProperties.computeMaxDurationPerAckExtension( - "subscription-name", projectIdProvider.getProjectId())) + gcpPubSubProperties.computeMaxDurationPerAckExtension( + "subscription-name", projectIdProvider.getProjectId())) .isEqualTo(6L); assertThat( - gcpPubSubProperties.computeParallelPullCount( - "subscription-name", projectIdProvider.getProjectId())) + gcpPubSubProperties.computeParallelPullCount( + "subscription-name", projectIdProvider.getProjectId())) .isEqualTo(12); assertThat( - gcpPubSubProperties.computePullEndpoint( - "subscription-name", projectIdProvider.getProjectId())) + gcpPubSubProperties.computePullEndpoint( + "subscription-name", projectIdProvider.getProjectId())) .isEqualTo("my-endpoint"); assertThat( - gcpPubSubProperties.computeMaxAckExtensionPeriod( - "other", projectIdProvider.getProjectId())) + gcpPubSubProperties.computeMaxAckExtensionPeriod( + "other", projectIdProvider.getProjectId())) .isEqualTo(5L); assertThat( - gcpPubSubProperties.computeMinDurationPerAckExtension( - "other", projectIdProvider.getProjectId())) + gcpPubSubProperties.computeMinDurationPerAckExtension( + "other", projectIdProvider.getProjectId())) .isEqualTo(3L); assertThat( - gcpPubSubProperties.computeMaxDurationPerAckExtension( - "other", projectIdProvider.getProjectId())) + gcpPubSubProperties.computeMaxDurationPerAckExtension( + "other", projectIdProvider.getProjectId())) .isEqualTo(4L); assertThat( - gcpPubSubProperties.computeParallelPullCount( - "other", projectIdProvider.getProjectId())) + gcpPubSubProperties.computeParallelPullCount( + "other", projectIdProvider.getProjectId())) .isEqualTo(10); assertThat( - gcpPubSubProperties.computePullEndpoint( - "other", projectIdProvider.getProjectId())) + gcpPubSubProperties.computePullEndpoint( + "other", projectIdProvider.getProjectId())) .isEqualTo("other-endpoint"); assertThat(gcpPubSubProperties.getFullyQualifiedSubscriberProperties()).hasSize(1); assertThat(gcpPubSubProperties.getFullyQualifiedSubscriberProperties()) - .containsKey(ProjectSubscriptionName.parse( - "projects/fake project/subscriptions/subscription-name")); + .containsKey( + ProjectSubscriptionName.parse( + "projects/fake project/subscriptions/subscription-name")); }); } @@ -728,28 +662,29 @@ void pullConfig_globalAndDifferentSelectiveConfigurationSet_pickGlobal() { GcpPubSubProperties gcpPubSubProperties = ctx.getBean(GcpPubSubProperties.class); GcpProjectIdProvider projectIdProvider = ctx.getBean(GcpProjectIdProvider.class); assertThat( - gcpPubSubProperties.computeMaxAckExtensionPeriod( - "subscription-name", projectIdProvider.getProjectId())) + gcpPubSubProperties.computeMaxAckExtensionPeriod( + "subscription-name", projectIdProvider.getProjectId())) .isEqualTo(5); assertThat( - gcpPubSubProperties.computeMinDurationPerAckExtension( - "subscription-name", projectIdProvider.getProjectId())) + gcpPubSubProperties.computeMinDurationPerAckExtension( + "subscription-name", projectIdProvider.getProjectId())) .isEqualTo(3); assertThat( - gcpPubSubProperties.computeMaxDurationPerAckExtension( - "subscription-name", projectIdProvider.getProjectId())) + gcpPubSubProperties.computeMaxDurationPerAckExtension( + "subscription-name", projectIdProvider.getProjectId())) .isEqualTo(4); assertThat( - gcpPubSubProperties.computeParallelPullCount( - "subscription-name", projectIdProvider.getProjectId())) + gcpPubSubProperties.computeParallelPullCount( + "subscription-name", projectIdProvider.getProjectId())) .isEqualTo(10); assertThat( - gcpPubSubProperties.computePullEndpoint( - "subscription-name", projectIdProvider.getProjectId())) + gcpPubSubProperties.computePullEndpoint( + "subscription-name", projectIdProvider.getProjectId())) .isEqualTo("other-endpoint"); assertThat(gcpPubSubProperties.getFullyQualifiedSubscriberProperties()) - .containsKey(ProjectSubscriptionName.parse( - "projects/fake project/subscriptions/subscription-name")); + .containsKey( + ProjectSubscriptionName.parse( + "projects/fake project/subscriptions/subscription-name")); }); } @@ -786,7 +721,8 @@ void retrySettings_globalConfigurationSet() { GcpProjectIdProvider projectIdProvider = ctx.getBean(GcpProjectIdProvider.class); PubSubConfiguration.Retry retrySettings = gcpPubSubProperties.computeSubscriberRetrySettings( - ProjectSubscriptionName.of(projectIdProvider.getProjectId(), "subscription-name")); + ProjectSubscriptionName.of( + projectIdProvider.getProjectId(), "subscription-name")); assertThat(retrySettings.getTotalTimeoutSeconds()).isEqualTo(1L); assertThat(retrySettings.getInitialRetryDelaySeconds()).isEqualTo(2L); assertThat(retrySettings.getRetryDelayMultiplier()).isEqualTo(3); @@ -810,8 +746,8 @@ void retrySettings_globalConfigurationSet() { .setRpcTimeoutMultiplier(7) .setMaxRpcTimeout(Duration.ofSeconds(8)) .build(); - assertThat(subscriberFactory.getRetrySettings("name")).isEqualTo( - expectedRetrySettings); + assertThat(subscriberFactory.getRetrySettings("name")) + .isEqualTo(expectedRetrySettings); assertThat(ctx.getBean("globalSubscriberRetrySettings", RetrySettings.class)) .isEqualTo(expectedRetrySettings); }); @@ -836,7 +772,8 @@ void retrySettings_selectiveConfigurationSet() { GcpProjectIdProvider projectIdProvider = ctx.getBean(GcpProjectIdProvider.class); PubSubConfiguration.Retry retrySettings = gcpPubSubProperties.computeSubscriberRetrySettings( - ProjectSubscriptionName.of(projectIdProvider.getProjectId(), "subscription-name")); + ProjectSubscriptionName.of( + projectIdProvider.getProjectId(), "subscription-name")); assertThat(retrySettings.getTotalTimeoutSeconds()).isEqualTo(1L); assertThat(retrySettings.getInitialRetryDelaySeconds()).isEqualTo(2L); assertThat(retrySettings.getRetryDelayMultiplier()).isEqualTo(3); @@ -848,8 +785,9 @@ void retrySettings_selectiveConfigurationSet() { assertThat(retrySettings.getMaxRpcTimeoutSeconds()).isEqualTo(8); assertThat(gcpPubSubProperties.getFullyQualifiedSubscriberProperties()).hasSize(1); assertThat(gcpPubSubProperties.getFullyQualifiedSubscriberProperties()) - .containsKey(ProjectSubscriptionName.parse( - "projects/fake project/subscriptions/subscription-name")); + .containsKey( + ProjectSubscriptionName.parse( + "projects/fake project/subscriptions/subscription-name")); DefaultSubscriberFactory subscriberFactory = ctx.getBean("defaultSubscriberFactory", DefaultSubscriberFactory.class); @@ -866,9 +804,10 @@ void retrySettings_selectiveConfigurationSet() { .build(); assertThat(subscriberFactory.getRetrySettings("subscription-name")) .isEqualTo(expectedRetrySettings); - assertThat(ctx.getBean( - "subscriberRetrySettings-projects/fake project/subscriptions/subscription-name", - RetrySettings.class)) + assertThat( + ctx.getBean( + "subscriberRetrySettings-projects/fake project/subscriptions/subscription-name", + RetrySettings.class)) .isEqualTo(expectedRetrySettings); }); } @@ -902,10 +841,12 @@ void retrySettings_globalAndSelectiveConfigurationSet_selectiveTakesPrecedence() // property set PubSubConfiguration.Retry retrySettings = gcpPubSubProperties.computeSubscriberRetrySettings( - ProjectSubscriptionName.of(projectIdProvider.getProjectId(), "subscription-name")); + ProjectSubscriptionName.of( + projectIdProvider.getProjectId(), "subscription-name")); assertThat(gcpPubSubProperties.getFullyQualifiedSubscriberProperties()) - .containsKey(ProjectSubscriptionName.parse( - "projects/fake project/subscriptions/subscription-name")); + .containsKey( + ProjectSubscriptionName.parse( + "projects/fake project/subscriptions/subscription-name")); assertThat(retrySettings.getTotalTimeoutSeconds()).isEqualTo(1L); assertThat(retrySettings.getInitialRetryDelaySeconds()).isEqualTo(2L); assertThat(retrySettings.getRetryDelayMultiplier()).isEqualTo(3); @@ -920,23 +861,25 @@ void retrySettings_globalAndSelectiveConfigurationSet_selectiveTakesPrecedence() // property set PubSubConfiguration.Retry retrySettingsForOtherSubscriber = gcpPubSubProperties - .getSubscriptionProperties(PubSubSubscriptionUtils - .toProjectSubscriptionName("other", projectIdProvider.getProjectId())) + .getSubscriptionProperties( + PubSubSubscriptionUtils.toProjectSubscriptionName( + "other", projectIdProvider.getProjectId())) .getRetry(); assertThat(retrySettingsForOtherSubscriber.getTotalTimeoutSeconds()).isEqualTo(10L); - assertThat(retrySettingsForOtherSubscriber.getInitialRetryDelaySeconds()).isEqualTo( - 10L); + assertThat(retrySettingsForOtherSubscriber.getInitialRetryDelaySeconds()) + .isEqualTo(10L); assertThat(retrySettingsForOtherSubscriber.getRetryDelayMultiplier()).isEqualTo(10); assertThat(retrySettingsForOtherSubscriber.getMaxRetryDelaySeconds()).isEqualTo(10); assertThat(retrySettingsForOtherSubscriber.getMaxAttempts()).isEqualTo(10); - assertThat(retrySettingsForOtherSubscriber.getInitialRpcTimeoutSeconds()).isEqualTo( - 10); + assertThat(retrySettingsForOtherSubscriber.getInitialRpcTimeoutSeconds()) + .isEqualTo(10); assertThat(retrySettingsForOtherSubscriber.getRpcTimeoutMultiplier()).isEqualTo(10); assertThat(retrySettingsForOtherSubscriber.getMaxRpcTimeoutSeconds()).isEqualTo(10); assertThat(gcpPubSubProperties.getFullyQualifiedSubscriberProperties()).hasSize(1); assertThat(gcpPubSubProperties.getFullyQualifiedSubscriberProperties()) - .containsKey(ProjectSubscriptionName.parse( - "projects/fake project/subscriptions/subscription-name")); + .containsKey( + ProjectSubscriptionName.parse( + "projects/fake project/subscriptions/subscription-name")); // Verify that beans for selective and global retry settings are created. Also // verify that selective retry setting takes precedence. @@ -966,9 +909,10 @@ void retrySettings_globalAndSelectiveConfigurationSet_selectiveTakesPrecedence() .build(); assertThat(subscriberFactory.getRetrySettings("subscription-name")) .isEqualTo(expectedRetrySettingsForSubscriptionName); - assertThat(ctx.getBean( - "subscriberRetrySettings-projects/fake project/subscriptions/subscription-name", - RetrySettings.class)) + assertThat( + ctx.getBean( + "subscriberRetrySettings-projects/fake project/subscriptions/subscription-name", + RetrySettings.class)) .isEqualTo(expectedRetrySettingsForSubscriptionName); assertThat(subscriberFactory.getRetrySettings("other")) .isEqualTo(expectedRetrySettingsForOther); @@ -997,7 +941,8 @@ void retrySettings_globalAndDifferentSelectiveConfigurationSet_pickGlobal() { PubSubConfiguration.Retry retrySettings = gcpPubSubProperties.computeSubscriberRetrySettings( - ProjectSubscriptionName.of(projectIdProvider.getProjectId(), "subscription-name")); + ProjectSubscriptionName.of( + projectIdProvider.getProjectId(), "subscription-name")); assertThat(retrySettings.getTotalTimeoutSeconds()).isEqualTo(10L); assertThat(retrySettings.getInitialRetryDelaySeconds()).isEqualTo(10L); assertThat(retrySettings.getRetryDelayMultiplier()).isEqualTo(10); @@ -1046,7 +991,8 @@ void retrySettings_subsetOfProperties_pickGlobalWhenSelectiveNotSpecified() { GcpProjectIdProvider projectIdProvider = ctx.getBean(GcpProjectIdProvider.class); PubSubConfiguration.Retry retry = gcpPubSubProperties.computeSubscriberRetrySettings( - ProjectSubscriptionName.of(projectIdProvider.getProjectId(), "subscription-name")); + ProjectSubscriptionName.of( + projectIdProvider.getProjectId(), "subscription-name")); assertThat(retry.getTotalTimeoutSeconds()).isEqualTo(10L); assertThat(retry.getInitialRetryDelaySeconds()).isEqualTo(2L); assertThat(retry.getRetryDelayMultiplier()).isEqualTo(3); @@ -1074,9 +1020,10 @@ void retrySettings_subsetOfProperties_pickGlobalWhenSelectiveNotSpecified() { RetrySettings.newBuilder().setTotalTimeout(Duration.ofSeconds(10L)).build(); assertThat(subscriberFactory.getRetrySettings("subscription-name")) .isEqualTo(expectedRetrySettingsForSubscriptionName); - assertThat(ctx.getBean( - "subscriberRetrySettings-projects/fake project/subscriptions/subscription-name", - RetrySettings.class)) + assertThat( + ctx.getBean( + "subscriberRetrySettings-projects/fake project/subscriptions/subscription-name", + RetrySettings.class)) .isEqualTo(expectedRetrySettingsForSubscriptionName); assertThat(ctx.getBean("globalSubscriberRetrySettings", RetrySettings.class)) .isEqualTo(expectedGlobalRetrySettings); @@ -1089,9 +1036,7 @@ void customFlowControlUsedWhenProvided() { contextRunner .withBean( - "subscriberFlowControlSettings", - FlowControlSettings.class, - () -> flowControlSettings) + "subscriberFlowControlSettings", FlowControlSettings.class, () -> flowControlSettings) .run( ctx -> { DefaultSubscriberFactory subscriberFactory = @@ -1123,16 +1068,16 @@ void flowControlSettings_globalConfigurationSet() { .setLimitExceededBehavior(FlowController.LimitExceededBehavior.Ignore) .build(); - assertThat(flowControlFromConfiguration.getMaxOutstandingElementCount()).isEqualTo( - 11L); - assertThat(flowControlFromConfiguration.getMaxOutstandingRequestBytes()).isEqualTo( - 12L); + assertThat(flowControlFromConfiguration.getMaxOutstandingElementCount()) + .isEqualTo(11L); + assertThat(flowControlFromConfiguration.getMaxOutstandingRequestBytes()) + .isEqualTo(12L); assertThat(flowControlFromConfiguration.getLimitExceededBehavior()) .isEqualTo(FlowController.LimitExceededBehavior.Ignore); assertThat(subscriberFactory.getFlowControlSettings("name")) .isEqualTo(expectedFlowControlSettings); assertThat( - ctx.getBean("globalSubscriberFlowControlSettings", FlowControlSettings.class)) + ctx.getBean("globalSubscriberFlowControlSettings", FlowControlSettings.class)) .isEqualTo(expectedFlowControlSettings); }); } @@ -1152,8 +1097,8 @@ void flowControlSettings_selectiveConfigurationSet() { PubSubConfiguration.FlowControl flowControl = gcpPubSubProperties .getSubscriptionProperties( - PubSubSubscriptionUtils - .toProjectSubscriptionName("subscription-name", projectIdProvider.getProjectId())) + PubSubSubscriptionUtils.toProjectSubscriptionName( + "subscription-name", projectIdProvider.getProjectId())) .getFlowControl(); assertThat(flowControl.getMaxOutstandingElementCount()).isEqualTo(11L); assertThat(flowControl.getMaxOutstandingRequestBytes()).isEqualTo(12L); @@ -1161,8 +1106,9 @@ void flowControlSettings_selectiveConfigurationSet() { .isEqualTo(FlowController.LimitExceededBehavior.Ignore); assertThat(gcpPubSubProperties.getFullyQualifiedSubscriberProperties()).hasSize(1); assertThat(gcpPubSubProperties.getFullyQualifiedSubscriberProperties()) - .containsKey(ProjectSubscriptionName.parse( - "projects/fake project/subscriptions/subscription-name")); + .containsKey( + ProjectSubscriptionName.parse( + "projects/fake project/subscriptions/subscription-name")); DefaultSubscriberFactory subscriberFactory = ctx.getBean("defaultSubscriberFactory", DefaultSubscriberFactory.class); @@ -1175,9 +1121,9 @@ void flowControlSettings_selectiveConfigurationSet() { assertThat(subscriberFactory.getFlowControlSettings("subscription-name")) .isEqualTo(expectedFlowControlForSubscriptionName); assertThat( - ctx.getBean( - "subscriberFlowControlSettings-projects/fake project/subscriptions/subscription-name", - FlowControlSettings.class)) + ctx.getBean( + "subscriberFlowControlSettings-projects/fake project/subscriptions/subscription-name", + FlowControlSettings.class)) .isEqualTo(expectedFlowControlForSubscriptionName); }); } @@ -1197,33 +1143,36 @@ void flowControlSettings_globalAndSelectiveConfigurationSet_selectiveTakesPreced GcpPubSubProperties gcpPubSubProperties = ctx.getBean(GcpPubSubProperties.class); GcpProjectIdProvider projectIdProvider = ctx.getBean(GcpProjectIdProvider.class); - // Validate settings for subscribers that have subscription-specific flow control settings + // Validate settings for subscribers that have subscription-specific flow control + // settings // property set PubSubConfiguration.FlowControl flowControl = gcpPubSubProperties.computeSubscriberFlowControlSettings( - ProjectSubscriptionName.of(projectIdProvider.getProjectId(), - "subscription-name")); + ProjectSubscriptionName.of( + projectIdProvider.getProjectId(), "subscription-name")); assertThat(flowControl.getMaxOutstandingElementCount()).isEqualTo(11L); assertThat(flowControl.getMaxOutstandingRequestBytes()).isEqualTo(12L); assertThat(flowControl.getLimitExceededBehavior()) .isEqualTo(FlowController.LimitExceededBehavior.Ignore); - // Validate settings for subscribers that do not have subscription-specific flow control + // Validate settings for subscribers that do not have subscription-specific flow + // control // settings property set PubSubConfiguration.FlowControl flowControlForOtherSubscriber = gcpPubSubProperties.computeSubscriberFlowControlSettings( ProjectSubscriptionName.of(projectIdProvider.getProjectId(), "other")); - assertThat(flowControlForOtherSubscriber.getMaxOutstandingElementCount()).isEqualTo( - 10L); - assertThat(flowControlForOtherSubscriber.getMaxOutstandingRequestBytes()).isEqualTo( - 10L); + assertThat(flowControlForOtherSubscriber.getMaxOutstandingElementCount()) + .isEqualTo(10L); + assertThat(flowControlForOtherSubscriber.getMaxOutstandingRequestBytes()) + .isEqualTo(10L); assertThat(flowControlForOtherSubscriber.getLimitExceededBehavior()) .isEqualTo(FlowController.LimitExceededBehavior.Block); // Change in behavior: calculated properties don't get stored assertThat(gcpPubSubProperties.getFullyQualifiedSubscriberProperties()).hasSize(1); assertThat(gcpPubSubProperties.getFullyQualifiedSubscriberProperties()) - .containsKey(ProjectSubscriptionName.parse( - "projects/fake project/subscriptions/subscription-name")); + .containsKey( + ProjectSubscriptionName.parse( + "projects/fake project/subscriptions/subscription-name")); // Verify that beans for selective and global flow control settings are created. DefaultSubscriberFactory subscriberFactory = @@ -1243,14 +1192,14 @@ void flowControlSettings_globalAndSelectiveConfigurationSet_selectiveTakesPreced assertThat(subscriberFactory.getFlowControlSettings("subscription-name")) .isEqualTo(expectedFlowControlForSubscriptionName); assertThat( - ctx.getBean( - "subscriberFlowControlSettings-projects/fake project/subscriptions/subscription-name", - FlowControlSettings.class)) + ctx.getBean( + "subscriberFlowControlSettings-projects/fake project/subscriptions/subscription-name", + FlowControlSettings.class)) .isEqualTo(expectedFlowControlForSubscriptionName); assertThat(subscriberFactory.getFlowControlSettings("other")) .isEqualTo(expectedFlowControlForOther); assertThat( - ctx.getBean("globalSubscriberFlowControlSettings", FlowControlSettings.class)) + ctx.getBean("globalSubscriberFlowControlSettings", FlowControlSettings.class)) .isEqualTo(expectedFlowControlForOther); }); } @@ -1270,16 +1219,17 @@ void flowControlSettings_globalAndDifferentSelectiveConfigurationSet_pickGlobal( PubSubConfiguration.FlowControl flowControl = gcpPubSubProperties.computeSubscriberFlowControlSettings( - ProjectSubscriptionName.of(projectIdProvider.getProjectId(), - "subscription-name")); + ProjectSubscriptionName.of( + projectIdProvider.getProjectId(), "subscription-name")); assertThat(flowControl.getMaxOutstandingElementCount()).isEqualTo(11L); assertThat(flowControl.getMaxOutstandingRequestBytes()).isEqualTo(12L); assertThat(flowControl.getLimitExceededBehavior()) .isEqualTo(FlowController.LimitExceededBehavior.Ignore); assertThat(gcpPubSubProperties.getFullyQualifiedSubscriberProperties()).hasSize(1); assertThat(gcpPubSubProperties.getFullyQualifiedSubscriberProperties()) - .containsKey(ProjectSubscriptionName.parse( - "projects/fake project/subscriptions/subscription-name")); + .containsKey( + ProjectSubscriptionName.parse( + "projects/fake project/subscriptions/subscription-name")); // Verify that bean for global flow control settings is created. DefaultSubscriberFactory subscriberFactory = @@ -1293,7 +1243,7 @@ void flowControlSettings_globalAndDifferentSelectiveConfigurationSet_pickGlobal( assertThat(subscriberFactory.getFlowControlSettings("subscription-name")) .isEqualTo(expectedFlowControlForSubscriptionName); assertThat( - ctx.getBean("globalSubscriberFlowControlSettings", FlowControlSettings.class)) + ctx.getBean("globalSubscriberFlowControlSettings", FlowControlSettings.class)) .isEqualTo(expectedFlowControlForSubscriptionName); }); } @@ -1313,8 +1263,8 @@ void flowControlSettings_subsetOfProperties_pickGlobalWhenSelectiveNotSpecified( PubSubConfiguration.FlowControl flowControl = gcpPubSubProperties.computeSubscriberFlowControlSettings( - ProjectSubscriptionName.of(projectIdProvider.getProjectId(), - "subscription-name")); + ProjectSubscriptionName.of( + projectIdProvider.getProjectId(), "subscription-name")); assertThat(flowControl.getMaxOutstandingElementCount()).isEqualTo(11L); assertThat(flowControl.getMaxOutstandingRequestBytes()).isEqualTo(12L); assertThat(flowControl.getLimitExceededBehavior()) @@ -1334,12 +1284,12 @@ void flowControlSettings_subsetOfProperties_pickGlobalWhenSelectiveNotSpecified( assertThat(subscriberFactory.getFlowControlSettings("subscription-name")) .isEqualTo(expectedFlowControlForSubscriptionName); assertThat( - ctx.getBean( - "subscriberFlowControlSettings-projects/fake project/subscriptions/subscription-name", - FlowControlSettings.class)) + ctx.getBean( + "subscriberFlowControlSettings-projects/fake project/subscriptions/subscription-name", + FlowControlSettings.class)) .isEqualTo(expectedFlowControlForSubscriptionName); assertThat( - ctx.getBean("globalSubscriberFlowControlSettings", FlowControlSettings.class)) + ctx.getBean("globalSubscriberFlowControlSettings", FlowControlSettings.class)) .isEqualTo(expectedGlobalSettings); }); } @@ -1351,8 +1301,7 @@ void createSubscriberStub_flowControlSettings_noPropertiesSet() { DefaultSubscriberFactory subscriberFactory = ctx.getBean("defaultSubscriberFactory", DefaultSubscriberFactory.class); Subscriber subscriber = - subscriberFactory.createSubscriber("subscription-name", (message, consumer) -> { - }); + subscriberFactory.createSubscriber("subscription-name", (message, consumer) -> {}); assertThat(subscriber.getFlowControlSettings()) .isEqualTo(Subscriber.Builder.getDefaultFlowControlSettings()); }); @@ -1362,24 +1311,25 @@ void createSubscriberStub_flowControlSettings_noPropertiesSet() { void createPublisherWithCustomizer() { contextRunner .withUserConfiguration(CustomizerConfig.class) - .run(ctx -> { - PublisherFactory factory = - ctx.getBean("defaultPublisherFactory", PublisherFactory.class); - - DefaultPublisherFactory defaultFactory = - (DefaultPublisherFactory) ((CachingPublisherFactory) factory).getDelegate(); - List customizers = - (List) FieldUtils.readField(defaultFactory, "customizers", true); - assertThat(customizers) - .hasSize(3); - assertThat(customizers.get(0)).isInstanceOf(NoopCustomizer.class); - assertThat(customizers.get(1)).isInstanceOf(NoopCustomizer.class); - // DefaultPublisherFactory applies highest priority last - assertThat(customizers.get(2)).isInstanceOf(BatchingSettingsCustomizer.class); - - Publisher testPublisher = factory.createPublisher("unused"); - assertThat(testPublisher.getBatchingSettings()).isSameAs(TEST_BATCHING_SETTINGS); - }); + .run( + ctx -> { + PublisherFactory factory = + ctx.getBean("defaultPublisherFactory", PublisherFactory.class); + + DefaultPublisherFactory defaultFactory = + (DefaultPublisherFactory) ((CachingPublisherFactory) factory).getDelegate(); + List customizers = + (List) + FieldUtils.readField(defaultFactory, "customizers", true); + assertThat(customizers).hasSize(3); + assertThat(customizers.get(0)).isInstanceOf(NoopCustomizer.class); + assertThat(customizers.get(1)).isInstanceOf(NoopCustomizer.class); + // DefaultPublisherFactory applies highest priority last + assertThat(customizers.get(2)).isInstanceOf(BatchingSettingsCustomizer.class); + + Publisher testPublisher = factory.createPublisher("unused"); + assertThat(testPublisher.getBatchingSettings()).isSameAs(TEST_BATCHING_SETTINGS); + }); } @Test @@ -1394,8 +1344,8 @@ void flowControlSettings_multipleKeysForSameSubscription_firstOneUsed(CapturedOu GcpPubSubProperties gcpPubSubProperties = ctx.getBean(GcpPubSubProperties.class); GcpProjectIdProvider projectIdProvider = ctx.getBean(GcpProjectIdProvider.class); - ProjectSubscriptionName projectSubscriptionName = ProjectSubscriptionName.of( - projectIdProvider.getProjectId(), "subscription-name"); + ProjectSubscriptionName projectSubscriptionName = + ProjectSubscriptionName.of(projectIdProvider.getProjectId(), "subscription-name"); PubSubConfiguration.FlowControl flowControl = gcpPubSubProperties .getSubscriptionProperties(projectSubscriptionName) @@ -1404,11 +1354,16 @@ void flowControlSettings_multipleKeysForSameSubscription_firstOneUsed(CapturedOu assertThat(gcpPubSubProperties.getFullyQualifiedSubscriberProperties()) .hasSize(1) .containsKey(projectSubscriptionName); - assertThat(gcpPubSubProperties.getFullyQualifiedSubscriberProperties() - .get(projectSubscriptionName).getFlowControl() - .getMaxOutstandingElementCount()).isEqualTo(100L); - assertThat(output).contains( - "Found multiple configurations for projects/fake project/subscriptions/subscription-name; ignoring properties with key synthetic-sub-name"); + assertThat( + gcpPubSubProperties + .getFullyQualifiedSubscriberProperties() + .get(projectSubscriptionName) + .getFlowControl() + .getMaxOutstandingElementCount()) + .isEqualTo(100L); + assertThat(output) + .contains( + "Found multiple configurations for projects/fake project/subscriptions/subscription-name; ignoring properties with key synthetic-sub-name"); }); } @@ -1481,7 +1436,6 @@ BatchingSettingsCustomizer batchingSettingsCustomizer() { NoopCustomizer noop2() { return new NoopCustomizer(); } - } static class NoopCustomizer implements PublisherCustomizer { diff --git a/spring-cloud-gcp-autoconfigure/src/test/java/com/google/cloud/spring/autoconfigure/pubsub/it/PubSubAutoConfigurationIntegrationTests.java b/spring-cloud-gcp-autoconfigure/src/test/java/com/google/cloud/spring/autoconfigure/pubsub/it/PubSubAutoConfigurationIntegrationTests.java index 0431941016..a1cf381e15 100644 --- a/spring-cloud-gcp-autoconfigure/src/test/java/com/google/cloud/spring/autoconfigure/pubsub/it/PubSubAutoConfigurationIntegrationTests.java +++ b/spring-cloud-gcp-autoconfigure/src/test/java/com/google/cloud/spring/autoconfigure/pubsub/it/PubSubAutoConfigurationIntegrationTests.java @@ -56,15 +56,18 @@ class PubSubAutoConfigurationIntegrationTests { private static GcpProjectIdProvider projectIdProvider; - private final String fullSubscriptionNameSub1 = "projects/" + projectIdProvider.getProjectId() + "/subscriptions/" + PULL_SUB; - private final String fullSubscriptionNameSub2 = "projects/" + projectIdProvider.getProjectId() + "/subscriptions/" + SUBSCRIBE_SUB; + private final String fullSubscriptionNameSub1 = + "projects/" + projectIdProvider.getProjectId() + "/subscriptions/" + PULL_SUB; + private final String fullSubscriptionNameSub2 = + "projects/" + projectIdProvider.getProjectId() + "/subscriptions/" + SUBSCRIBE_SUB; private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() .withPropertyValues( "spring.cloud.gcp.pubsub.subscriber.retryableCodes=INTERNAL", "spring.cloud.gcp.pubsub.subscription.fully-qualified-test-sub-1-with-project-abc.executor-threads=3", - "spring.cloud.gcp.pubsub.subscription.fully-qualified-test-sub-1-with-project-abc.fully-qualified-name=" + fullSubscriptionNameSub1, + "spring.cloud.gcp.pubsub.subscription.fully-qualified-test-sub-1-with-project-abc.fully-qualified-name=" + + fullSubscriptionNameSub1, "spring.cloud.gcp.pubsub.subscription.fully-qualified-test-sub-1-with-project-abc.retry.total-timeout-seconds=600", "spring.cloud.gcp.pubsub.subscription.fully-qualified-test-sub-1-with-project-abc.retry.initial-retry-delay-seconds=100", "spring.cloud.gcp.pubsub.subscription.fully-qualified-test-sub-1-with-project-abc.retry.retry-delay-multiplier=1.3", @@ -75,14 +78,28 @@ class PubSubAutoConfigurationIntegrationTests { "spring.cloud.gcp.pubsub.subscription.fully-qualified-test-sub-1-with-project-abc.retry.max-rpc-timeout-seconds=600", "spring.cloud.gcp.pubsub.subscription.fully-qualified-test-sub-1-with-project-abc.pull-endpoint=northamerica-northeast2-pubsub.googleapis.com:443", "spring.cloud.gcp.pubsub.subscription." + SUBSCRIBE_SUB + ".executor-threads=1", - "spring.cloud.gcp.pubsub.subscription." + SUBSCRIBE_SUB + ".max-ack-extension-period=0", - "spring.cloud.gcp.pubsub.subscription." + SUBSCRIBE_SUB + ".min-duration-per-ack-extension=1", - "spring.cloud.gcp.pubsub.subscription." + SUBSCRIBE_SUB + ".max-duration-per-ack-extension=2", + "spring.cloud.gcp.pubsub.subscription." + + SUBSCRIBE_SUB + + ".max-ack-extension-period=0", + "spring.cloud.gcp.pubsub.subscription." + + SUBSCRIBE_SUB + + ".min-duration-per-ack-extension=1", + "spring.cloud.gcp.pubsub.subscription." + + SUBSCRIBE_SUB + + ".max-duration-per-ack-extension=2", "spring.cloud.gcp.pubsub.subscription." + SUBSCRIBE_SUB + ".parallel-pull-count=1", - "spring.cloud.gcp.pubsub.subscription." + SUBSCRIBE_SUB + ".flow-control.max-outstanding-element-Count=1", - "spring.cloud.gcp.pubsub.subscription." + SUBSCRIBE_SUB + ".flow-control.max-outstanding-request-Bytes=1", - "spring.cloud.gcp.pubsub.subscription." + SUBSCRIBE_SUB + ".flow-control.limit-exceeded-behavior=Ignore", - "spring.cloud.gcp.pubsub.subscription." + SUBSCRIBE_SUB + ".pull-endpoint=bad.endpoint") + "spring.cloud.gcp.pubsub.subscription." + + SUBSCRIBE_SUB + + ".flow-control.max-outstanding-element-Count=1", + "spring.cloud.gcp.pubsub.subscription." + + SUBSCRIBE_SUB + + ".flow-control.max-outstanding-request-Bytes=1", + "spring.cloud.gcp.pubsub.subscription." + + SUBSCRIBE_SUB + + ".flow-control.limit-exceeded-behavior=Ignore", + "spring.cloud.gcp.pubsub.subscription." + + SUBSCRIBE_SUB + + ".pull-endpoint=bad.endpoint") .withConfiguration( AutoConfigurations.of( GcpContextAutoConfiguration.class, GcpPubSubAutoConfiguration.class)); @@ -137,29 +154,25 @@ void testPull() { assertThat(retry.getRpcTimeoutMultiplier()).isEqualTo(1); assertThat(retry.getMaxRpcTimeoutSeconds()).isEqualTo(600L); ThreadPoolTaskScheduler scheduler = - (ThreadPoolTaskScheduler) context.getBean( - "threadPoolScheduler_" + fullSubscriptionNameSub1); + (ThreadPoolTaskScheduler) + context.getBean("threadPoolScheduler_" + fullSubscriptionNameSub1); assertThat(scheduler).isNotNull(); - assertThat(scheduler.getThreadNamePrefix()).isEqualTo( - "gcp-pubsub-subscriber-" + fullSubscriptionNameSub1); + assertThat(scheduler.getThreadNamePrefix()) + .isEqualTo("gcp-pubsub-subscriber-" + fullSubscriptionNameSub1); assertThat(scheduler.isDaemon()).isTrue(); assertThat( - (ThreadPoolTaskScheduler) - context.getBean("globalPubSubSubscriberThreadPoolScheduler")) - .isNotNull(); - assertThat((ExecutorProvider) context.getBean( - "subscriberExecutorProvider-" + fullSubscriptionNameSub1)) - .isNotNull(); - assertThat((ExecutorProvider) context.getBean("globalSubscriberExecutorProvider")) + (ExecutorProvider) + context.getBean("subscriberExecutorProvider-" + fullSubscriptionNameSub1)) .isNotNull(); assertThat(gcpPubSubProperties.computeRetryableCodes(subscriptionName, projectId)) - .isEqualTo(new Code[]{Code.INTERNAL}); + .isEqualTo(new Code[] {Code.INTERNAL}); assertThat(gcpPubSubProperties.computePullEndpoint(fullSubscriptionNameSub1, projectId)) .isEqualTo("northamerica-northeast2-pubsub.googleapis.com:443"); assertThat(gcpPubSubProperties.computePullEndpoint(SUBSCRIBE_SUB, projectId)) .isEqualTo("bad.endpoint"); - assertThat((RetrySettings) context.getBean( - "subscriberRetrySettings-" + fullSubscriptionNameSub1)) + assertThat( + (RetrySettings) + context.getBean("subscriberRetrySettings-" + fullSubscriptionNameSub1)) .isEqualTo(expectedRetrySettings); } finally { pubSubAdmin.deleteSubscription(subscriptionName); @@ -172,7 +185,6 @@ void testPull() { void testSubscribe() { this.contextRunner.run( context -> { - PubSubAdmin pubSubAdmin = context.getBean(PubSubAdmin.class); PubSubTemplate pubSubTemplate = context.getBean(PubSubTemplate.class); @@ -210,44 +222,37 @@ void testSubscribe() { .setLimitExceededBehavior(FlowController.LimitExceededBehavior.Ignore) .build(); assertThat( - (FlowControlSettings) context.getBean( - "subscriberFlowControlSettings-" + fullSubscriptionNameSub2)) + (FlowControlSettings) + context.getBean( + "subscriberFlowControlSettings-" + fullSubscriptionNameSub2)) .isEqualTo(flowControlSettings); assertThat(flowControl.getMaxOutstandingElementCount()).isEqualTo(1L); assertThat(flowControl.getMaxOutstandingRequestBytes()).isEqualTo(1L); assertThat(flowControl.getLimitExceededBehavior()) .isEqualTo(FlowController.LimitExceededBehavior.Ignore); assertThat( - gcpPubSubProperties.computeMaxAckExtensionPeriod( - subscriptionName, projectId)) + gcpPubSubProperties.computeMaxAckExtensionPeriod(subscriptionName, projectId)) .isZero(); assertThat( - gcpPubSubProperties.computeMinDurationPerAckExtension( - subscriptionName, projectId)) + gcpPubSubProperties.computeMinDurationPerAckExtension( + subscriptionName, projectId)) .isEqualTo(1L); assertThat( - gcpPubSubProperties.computeMaxDurationPerAckExtension( - subscriptionName, projectId)) + gcpPubSubProperties.computeMaxDurationPerAckExtension( + subscriptionName, projectId)) .isEqualTo(2L); - assertThat( - gcpPubSubProperties.computeParallelPullCount( - subscriptionName, projectId)) + assertThat(gcpPubSubProperties.computeParallelPullCount(subscriptionName, projectId)) .isEqualTo(1); ThreadPoolTaskScheduler scheduler = - (ThreadPoolTaskScheduler) context.getBean( - "threadPoolScheduler_" + fullSubscriptionNameSub2); + (ThreadPoolTaskScheduler) + context.getBean("threadPoolScheduler_" + fullSubscriptionNameSub2); assertThat(scheduler).isNotNull(); - assertThat(scheduler.getThreadNamePrefix()).isEqualTo( - "gcp-pubsub-subscriber-" + fullSubscriptionNameSub2); + assertThat(scheduler.getThreadNamePrefix()) + .isEqualTo("gcp-pubsub-subscriber-" + fullSubscriptionNameSub2); assertThat(scheduler.isDaemon()).isTrue(); assertThat( - (ThreadPoolTaskScheduler) - context.getBean("globalPubSubSubscriberThreadPoolScheduler")) - .isNotNull(); - assertThat((ExecutorProvider) context.getBean( - "subscriberExecutorProvider-" + fullSubscriptionNameSub2)) - .isNotNull(); - assertThat((ExecutorProvider) context.getBean("globalSubscriberExecutorProvider")) + (ExecutorProvider) + context.getBean("subscriberExecutorProvider-" + fullSubscriptionNameSub2)) .isNotNull(); } finally { pubSubAdmin.deleteSubscription(subscriptionName); diff --git a/spring-cloud-gcp-pubsub/src/main/java/com/google/cloud/spring/pubsub/core/PubSubConfiguration.java b/spring-cloud-gcp-pubsub/src/main/java/com/google/cloud/spring/pubsub/core/PubSubConfiguration.java index f9cf3513e3..6e253e0090 100644 --- a/spring-cloud-gcp-pubsub/src/main/java/com/google/cloud/spring/pubsub/core/PubSubConfiguration.java +++ b/spring-cloud-gcp-pubsub/src/main/java/com/google/cloud/spring/pubsub/core/PubSubConfiguration.java @@ -34,11 +34,6 @@ public class PubSubConfiguration { private static final Logger logger = LoggerFactory.getLogger(PubSubConfiguration.class); - /** Default number of executor threads. */ - public static final int DEFAULT_EXECUTOR_THREADS = 5; - - private static final Long DEFAULT_MAX_ACK_EXTENSION_PERIOD = 3600L; - /** * Automatically extracted user-provided properties. Contains only short subscription keys * user-provided properties, therefore do not use except in initialize(). @@ -225,10 +220,7 @@ public Long computeMaxAckExtensionPeriod(String subscriptionName, String project if (maxAckExtensionPeriod != null) { return maxAckExtensionPeriod; } - Long globalMaxAckExtensionPeriod = this.globalSubscriber.getMaxAckExtensionPeriod(); - return globalMaxAckExtensionPeriod != null - ? globalMaxAckExtensionPeriod - : DEFAULT_MAX_ACK_EXTENSION_PERIOD; + return this.globalSubscriber.getMaxAckExtensionPeriod(); } /** diff --git a/spring-cloud-gcp-pubsub/src/main/java/com/google/cloud/spring/pubsub/support/DefaultSubscriberFactory.java b/spring-cloud-gcp-pubsub/src/main/java/com/google/cloud/spring/pubsub/support/DefaultSubscriberFactory.java index 1ba9347b97..41b020728f 100644 --- a/spring-cloud-gcp-pubsub/src/main/java/com/google/cloud/spring/pubsub/support/DefaultSubscriberFactory.java +++ b/spring-cloud-gcp-pubsub/src/main/java/com/google/cloud/spring/pubsub/support/DefaultSubscriberFactory.java @@ -89,9 +89,8 @@ public class DefaultSubscriberFactory implements SubscriberFactory { private RetrySettings globalRetrySettings; - private Map executorProviderMap = new ConcurrentHashMap<>(); - - private ExecutorProvider globalExecutorProvider; + private Map executorProviderMap = + new ConcurrentHashMap<>(); private Code[] retryableCodes; @@ -307,7 +306,6 @@ public Subscriber createSubscriber(String subscriptionName, MessageReceiver rece subscriberBuilder.setUniverseDomain(universeDomain); } - Subscriber subscriber = subscriberBuilder.build(); if (shouldAddToHealthCheck) { @@ -362,8 +360,7 @@ SubscriberStubSettings buildGlobalSubscriberStubSettings() throws IOException { subscriberStubSettings.setEndpoint(endpoint); } - ExecutorProvider executor = - this.executorProvider != null ? this.executorProvider : this.globalExecutorProvider; + ExecutorProvider executor = this.executorProvider; if (executor != null) { subscriberStubSettings.setBackgroundExecutorProvider(executor); } @@ -452,7 +449,7 @@ public ExecutorProvider getExecutorProvider(String subscriptionName) { if (this.executorProviderMap.containsKey(projectSubscriptionName)) { return this.executorProviderMap.get(projectSubscriptionName); } - return this.globalExecutorProvider; + return null; } /** @@ -499,8 +496,12 @@ Duration getMaxAckExtensionPeriod(String subscriptionName) { if (this.maxAckExtensionPeriod != null) { return this.maxAckExtensionPeriod; } - return Duration.ofSeconds( - this.pubSubConfiguration.computeMaxAckExtensionPeriod(subscriptionName, projectId)); + Long maxAckExtensionPeriod = + this.pubSubConfiguration.computeMaxAckExtensionPeriod(subscriptionName, projectId); + if (maxAckExtensionPeriod != null) { + return Duration.ofSeconds(maxAckExtensionPeriod); + } + return null; } @Nullable @@ -572,18 +573,11 @@ String getUniverseDomain(String subscriptionName) { return this.pubSubConfiguration.computeSubscriberUniverseDomain(subscriptionName, projectId); } - public void setExecutorProviderMap(Map executorProviderMap) { + public void setExecutorProviderMap( + Map executorProviderMap) { this.executorProviderMap = executorProviderMap; } - public void setGlobalExecutorProvider(ExecutorProvider executorProvider) { - this.globalExecutorProvider = executorProvider; - } - - public ExecutorProvider getGlobalExecutorProvider() { - return this.globalExecutorProvider; - } - public void setFlowControlSettingsMap( Map flowControlSettingsMap) { this.flowControlSettingsMap = flowControlSettingsMap; diff --git a/spring-cloud-gcp-pubsub/src/test/java/com/google/cloud/spring/pubsub/core/PubSubConfigurationTests.java b/spring-cloud-gcp-pubsub/src/test/java/com/google/cloud/spring/pubsub/core/PubSubConfigurationTests.java index f1c6e4f43f..81341f89ce 100644 --- a/spring-cloud-gcp-pubsub/src/test/java/com/google/cloud/spring/pubsub/core/PubSubConfigurationTests.java +++ b/spring-cloud-gcp-pubsub/src/test/java/com/google/cloud/spring/pubsub/core/PubSubConfigurationTests.java @@ -265,7 +265,7 @@ void testComputeMaxAckExtensionPeriod_returnDefault() { Long result = pubSubConfiguration.computeMaxAckExtensionPeriod("subscription-name", "projectId"); - assertThat(result).isEqualTo(3600L); + assertThat(result).isNull(); } @Test diff --git a/spring-cloud-gcp-pubsub/src/test/java/com/google/cloud/spring/pubsub/support/DefaultSubscriberFactoryTests.java b/spring-cloud-gcp-pubsub/src/test/java/com/google/cloud/spring/pubsub/support/DefaultSubscriberFactoryTests.java index 5441fdb335..951f0da9d9 100644 --- a/spring-cloud-gcp-pubsub/src/test/java/com/google/cloud/spring/pubsub/support/DefaultSubscriberFactoryTests.java +++ b/spring-cloud-gcp-pubsub/src/test/java/com/google/cloud/spring/pubsub/support/DefaultSubscriberFactoryTests.java @@ -93,6 +93,23 @@ void testNewSubscriber() { .isEqualTo("projects/angeldust/subscriptions/midnight cowboy"); } + @Test + void testNewSubscriber_noMaxAckExtensionPeriodSet_usesClientDefault() + throws NoSuchFieldException, IllegalAccessException { + DefaultSubscriberFactory factory = new DefaultSubscriberFactory(() -> "sealion", pubSubConfig); + String subscriptionName = "deadbeef"; + + // By default, we build a subscriber with null max ack extension period + Duration maxAckExtensionPeriodArgument = factory.getMaxAckExtensionPeriod(subscriptionName); + assertThat(maxAckExtensionPeriodArgument).isNull(); + + // Now we check that the default in google-cloud-pubsub was used + Subscriber subscriber = factory.createSubscriber(subscriptionName, (message, consumer) -> {}); + java.time.Duration effectiveMaxAckExtensionPeriod = (java.time.Duration) FieldUtils.readField(subscriber, "maxAckExtensionPeriod", true); + java.time.Duration clientDefaultMaxAckExtensionPeriod = (java.time.Duration) FieldUtils.readField(subscriber, "DEFAULT_MAX_ACK_EXTENSION_PERIOD", true); + assertThat(effectiveMaxAckExtensionPeriod).isEqualTo(clientDefaultMaxAckExtensionPeriod); + } + @Test void testNewSubscriber_constructorWithPubSubConfiguration() { GcpProjectIdProvider projectIdProvider = () -> "angeldust"; @@ -534,7 +551,7 @@ void testGetMaxAckExtensionPeriod_newConfiguration() { new DefaultSubscriberFactory(projectIdProvider, this.pubSubConfig); assertThat(factory.getMaxAckExtensionPeriod("subscription-name")) - .isEqualTo(Duration.ofSeconds(3600L)); + .isNull(); } @Test From 136a6ef76d419a6b7750ee61dd9f34b5dac0edca Mon Sep 17 00:00:00 2001 From: Diego Alonso Marquez Palacios Date: Wed, 29 Jan 2025 22:28:00 -0500 Subject: [PATCH 06/11] deformat --- .../pubsub/GcpPubSubAutoConfiguration.java | 26 +- .../GcpPubSubAutoConfigurationTests.java | 493 +++++++++--------- ...bSubAutoConfigurationIntegrationTests.java | 91 ++-- .../support/DefaultSubscriberFactory.java | 10 +- 4 files changed, 285 insertions(+), 335 deletions(-) diff --git a/spring-cloud-gcp-autoconfigure/src/main/java/com/google/cloud/spring/autoconfigure/pubsub/GcpPubSubAutoConfiguration.java b/spring-cloud-gcp-autoconfigure/src/main/java/com/google/cloud/spring/autoconfigure/pubsub/GcpPubSubAutoConfiguration.java index 73ee2a2716..83cc15164a 100644 --- a/spring-cloud-gcp-autoconfigure/src/main/java/com/google/cloud/spring/autoconfigure/pubsub/GcpPubSubAutoConfiguration.java +++ b/spring-cloud-gcp-autoconfigure/src/main/java/com/google/cloud/spring/autoconfigure/pubsub/GcpPubSubAutoConfiguration.java @@ -370,8 +370,8 @@ public PublisherFactory defaultPublisherFactory( factory.setEndpoint(gcpPubSubProperties.getPublisher().getEndpoint()); factory.setUniverseDomain(gcpPubSubProperties.getPublisher().getUniverseDomain()); - List customizers = - customizersProvider.orderedStream().collect(Collectors.toList()); + List customizers = customizersProvider.orderedStream() + .collect(Collectors.toList()); Collections.reverse(customizers); // highest priority customizer needs to be last factory.setCustomizers(customizers); @@ -433,8 +433,7 @@ public SubscriptionAdminClient subscriptionAdminClient( public TransportChannelProvider subscriberTransportChannelProvider() { return SubscriberStubSettings.defaultGrpcTransportProviderBuilder() // default value specified by pubsub client library, - // see - // https://github.com/googleapis/java-pubsub/blob/main/google-cloud-pubsub/src/main/java/com/google/cloud/pubsub/v1/Subscriber.java#L487. + // see https://github.com/googleapis/java-pubsub/blob/main/google-cloud-pubsub/src/main/java/com/google/cloud/pubsub/v1/Subscriber.java#L487. .setMaxInboundMetadataSize(4 * 1024 * 1024) .setKeepAliveTime( Duration.ofMinutes(this.gcpPubSubProperties.getKeepAliveIntervalMinutes())) @@ -517,12 +516,10 @@ private void registerSelectiveSchedulerBeans(GenericApplicationContext context) Integer selectiveExecutorThreads = selectiveSubscriber.getExecutorThreads(); if (selectiveExecutorThreads != null) { String qualifiedName = fullSubscriptionName.toString(); // will include slashes - String threadName = - selectiveSchedulerThreadNameProvider - .getIfAvailable( - () -> - subscriptionName -> "gcp-pubsub-subscriber-" + subscriptionName.toString()) - .getThreadName(fullSubscriptionName); + String threadName = selectiveSchedulerThreadNameProvider + .getIfAvailable( + () -> subscriptionName -> "gcp-pubsub-subscriber-" + subscriptionName.toString()) + .getThreadName(fullSubscriptionName); String beanName = "threadPoolScheduler_" + qualifiedName; ThreadPoolTaskScheduler selectiveScheduler = createAndRegisterSchedulerBean(selectiveExecutorThreads, threadName, beanName, context); @@ -546,11 +543,10 @@ private ThreadPoolTaskScheduler createAndRegisterSchedulerBean( String beanName, GenericApplicationContext context) { ThreadPoolTaskScheduler scheduler; - scheduler = - executorThreads == null ? null : createThreadPoolTaskScheduler(executorThreads, threadName); + scheduler = executorThreads == null ? null : createThreadPoolTaskScheduler(executorThreads, threadName); context.registerBeanDefinition( beanName, - BeanDefinitionBuilder.genericBeanDefinition(ThreadPoolTaskScheduler.class, () -> scheduler) + BeanDefinitionBuilder.genericBeanDefinition(ThreadPoolTaskScheduler.class, () -> scheduler) .getBeanDefinition()); return scheduler; } @@ -606,7 +602,9 @@ private void createAndRegisterSelectiveExecutorProvider(GenericApplicationContex ThreadPoolTaskScheduler scheduler = schedulerSet.getValue(); ExecutorProvider executorProvider = createAndRegisterExecutorProvider( - "subscriberExecutorProvider-" + qualifiedName, scheduler, context); + "subscriberExecutorProvider-" + qualifiedName, + scheduler, + context); this.executorProviderMap.putIfAbsent(fullSubscriptionName, executorProvider); } } diff --git a/spring-cloud-gcp-autoconfigure/src/test/java/com/google/cloud/spring/autoconfigure/pubsub/GcpPubSubAutoConfigurationTests.java b/spring-cloud-gcp-autoconfigure/src/test/java/com/google/cloud/spring/autoconfigure/pubsub/GcpPubSubAutoConfigurationTests.java index cd6396d8f0..4b4dddf0d3 100644 --- a/spring-cloud-gcp-autoconfigure/src/test/java/com/google/cloud/spring/autoconfigure/pubsub/GcpPubSubAutoConfigurationTests.java +++ b/spring-cloud-gcp-autoconfigure/src/test/java/com/google/cloud/spring/autoconfigure/pubsub/GcpPubSubAutoConfigurationTests.java @@ -58,21 +58,23 @@ import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; import org.threeten.bp.Duration; -/** Tests for Pub/Sub autoconfiguration. */ +/** + * Tests for Pub/Sub autoconfiguration. + */ @ExtendWith(OutputCaptureExtension.class) class GcpPubSubAutoConfigurationTests { private ApplicationContextRunner contextRunner; - static final BatchingSettings TEST_BATCHING_SETTINGS = - BatchingSettings.newBuilder().setDelayThreshold(Duration.ofSeconds(11)).build(); + static final BatchingSettings TEST_BATCHING_SETTINGS = BatchingSettings.newBuilder() + .setDelayThreshold(Duration.ofSeconds(11)) + .build(); @BeforeEach void init() { - contextRunner = - new ApplicationContextRunner() - .withConfiguration(AutoConfigurations.of(GcpPubSubAutoConfiguration.class)) - .withUserConfiguration(TestConfig.class); + contextRunner = new ApplicationContextRunner() + .withConfiguration(AutoConfigurations.of(GcpPubSubAutoConfiguration.class)) + .withUserConfiguration(TestConfig.class); } @Test @@ -87,18 +89,17 @@ void keepAliveValue_default() { TransportChannelProvider publisherTcp = ctx.getBean("publisherTransportChannelProvider", TransportChannelProvider.class); assertThat( - ((InstantiatingGrpcChannelProvider) subscriberTcp).getKeepAliveTime().toMinutes()) + ((InstantiatingGrpcChannelProvider) subscriberTcp).getKeepAliveTime().toMinutes()) .isEqualTo(5); assertThat( - ((InstantiatingGrpcChannelProvider) publisherTcp).getKeepAliveTime().toMinutes()) + ((InstantiatingGrpcChannelProvider) publisherTcp).getKeepAliveTime().toMinutes()) .isEqualTo(5); }); } @Test void keepAliveValue_custom() { - contextRunner - .withPropertyValues("spring.cloud.gcp.pubsub.keepAliveIntervalMinutes=2") + contextRunner.withPropertyValues("spring.cloud.gcp.pubsub.keepAliveIntervalMinutes=2") .run( ctx -> { GcpPubSubProperties props = ctx.getBean(GcpPubSubProperties.class); @@ -109,14 +110,10 @@ void keepAliveValue_custom() { TransportChannelProvider publisherTcp = ctx.getBean("publisherTransportChannelProvider", TransportChannelProvider.class); assertThat( - ((InstantiatingGrpcChannelProvider) subscriberTcp) - .getKeepAliveTime() - .toMinutes()) + ((InstantiatingGrpcChannelProvider) subscriberTcp).getKeepAliveTime().toMinutes()) .isEqualTo(2); assertThat( - ((InstantiatingGrpcChannelProvider) publisherTcp) - .getKeepAliveTime() - .toMinutes()) + ((InstantiatingGrpcChannelProvider) publisherTcp).getKeepAliveTime().toMinutes()) .isEqualTo(2); }); } @@ -154,15 +151,10 @@ void defaultSubscriberFactory_noExecutorThreadsSet_usesClientDefault() { ctx -> { DefaultSubscriberFactory defaultSubscriberFactory = ctx.getBean("defaultSubscriberFactory", DefaultSubscriberFactory.class); - Subscriber subscriber = - defaultSubscriberFactory.createSubscriber("dead10cc", (message, consumer) -> {}); - // we confirm that the created subscriber uses the default thread setting in the client (5 - // as of Jan 2025). - InstantiatingExecutorProvider executorProvider = - (InstantiatingExecutorProvider) - FieldUtils.readField(subscriber, "executorProvider", true); - Integer threadsPerChannel = - (Integer) FieldUtils.readField(subscriber, "THREADS_PER_CHANNEL", true); + Subscriber subscriber = defaultSubscriberFactory.createSubscriber("dead10cc", (message, consumer) -> {}); + // we confirm that the created subscriber uses the default thread setting in the client (5 as of Jan 2025). + InstantiatingExecutorProvider executorProvider = (InstantiatingExecutorProvider) FieldUtils.readField(subscriber, "executorProvider", true); + Integer threadsPerChannel = (Integer) FieldUtils.readField(subscriber, "THREADS_PER_CHANNEL", true); assertThat(executorProvider.getExecutorThreadCount()).isEqualTo(threadsPerChannel); }); } @@ -190,13 +182,13 @@ void retryableCodes_empty() { DefaultSubscriberFactory defaultSubscriberFactory = ctx.getBean("defaultSubscriberFactory", DefaultSubscriberFactory.class); - assertThat(properties.getSubscriber().getRetryableCodes()).isEqualTo(new Code[] {}); + assertThat(properties.getSubscriber().getRetryableCodes()).isEqualTo(new Code[]{}); assertThat( - properties.computeRetryableCodes( - "subscription-name", projectIdProvider.getProjectId())) - .isEqualTo(new Code[] {}); + properties.computeRetryableCodes( + "subscription-name", projectIdProvider.getProjectId())) + .isEqualTo(new Code[]{}); assertThat(defaultSubscriberFactory.getRetryableCodes("subscription-name")) - .isEqualTo(new Code[] {}); + .isEqualTo(new Code[]{}); }); } @@ -212,13 +204,13 @@ void retryableCodes_Internal() { ctx.getBean("defaultSubscriberFactory", DefaultSubscriberFactory.class); assertThat(properties.getSubscriber().getRetryableCodes()) - .isEqualTo(new Code[] {Code.INTERNAL}); + .isEqualTo(new Code[]{Code.INTERNAL}); assertThat( - properties.computeRetryableCodes( - "subscription-name", projectIdProvider.getProjectId())) - .isEqualTo(new Code[] {Code.INTERNAL}); + properties.computeRetryableCodes( + "subscription-name", projectIdProvider.getProjectId())) + .isEqualTo(new Code[]{Code.INTERNAL}); assertThat(defaultSubscriberFactory.getRetryableCodes("subscription-name")) - .isEqualTo(new Code[] {Code.INTERNAL}); + .isEqualTo(new Code[]{Code.INTERNAL}); }); } @@ -234,13 +226,13 @@ void retryableCodes_many() { DefaultSubscriberFactory defaultSubscriberFactory = ctx.getBean("defaultSubscriberFactory", DefaultSubscriberFactory.class); Code[] expectedRetryableCodes = - new Code[] {Code.UNKNOWN, Code.ABORTED, Code.UNAVAILABLE, Code.INTERNAL}; + new Code[]{Code.UNKNOWN, Code.ABORTED, Code.UNAVAILABLE, Code.INTERNAL}; assertThat(properties.getSubscriber().getRetryableCodes()) .isEqualTo(expectedRetryableCodes); assertThat( - properties.computeRetryableCodes( - "subscription-name", projectIdProvider.getProjectId())) + properties.computeRetryableCodes( + "subscription-name", projectIdProvider.getProjectId())) .isEqualTo(expectedRetryableCodes); assertThat(defaultSubscriberFactory.getRetryableCodes("subscription-name")) .isEqualTo(expectedRetryableCodes); @@ -258,7 +250,7 @@ void retryableCodes_selectiveConfigurationSet() { ctx.getBean("defaultSubscriberFactory", DefaultSubscriberFactory.class); assertThat(defaultSubscriberFactory.getRetryableCodes("subscription-name")) .isEqualTo( - new Code[] {Code.UNKNOWN, Code.ABORTED, Code.UNAVAILABLE, Code.INTERNAL}); + new Code[]{Code.UNKNOWN, Code.ABORTED, Code.UNAVAILABLE, Code.INTERNAL}); assertThat(defaultSubscriberFactory.getRetryableCodes("other")).isNull(); }); } @@ -274,9 +266,9 @@ void retryableCodes_globalAndSelectiveConfigurationSet_selectiveTakesPrecedence( DefaultSubscriberFactory defaultSubscriberFactory = ctx.getBean("defaultSubscriberFactory", DefaultSubscriberFactory.class); assertThat(defaultSubscriberFactory.getRetryableCodes("subscription-name")) - .isEqualTo(new Code[] {Code.UNKNOWN, Code.ABORTED, Code.UNAVAILABLE}); + .isEqualTo(new Code[]{Code.UNKNOWN, Code.ABORTED, Code.UNAVAILABLE}); assertThat(defaultSubscriberFactory.getRetryableCodes("other")) - .isEqualTo(new Code[] {Code.INTERNAL}); + .isEqualTo(new Code[]{Code.INTERNAL}); }); } @@ -291,7 +283,7 @@ void retryableCodes_globalAndDifferentSelectiveConfigurationSet_pickGlobal() { DefaultSubscriberFactory defaultSubscriberFactory = ctx.getBean("defaultSubscriberFactory", DefaultSubscriberFactory.class); assertThat(defaultSubscriberFactory.getRetryableCodes("subscription-name")) - .isEqualTo(new Code[] {Code.INTERNAL}); + .isEqualTo(new Code[]{Code.INTERNAL}); }); } @@ -321,6 +313,7 @@ void subscriberThreadPoolTaskScheduler_globalConfigurationSet() { }); } + @Test void threadPoolTaskScheduler_selectiveConfigurationSet() { contextRunner @@ -331,9 +324,8 @@ void threadPoolTaskScheduler_selectiveConfigurationSet() { // Verify that selective and global beans have been created ThreadPoolTaskScheduler selectiveScheduler = - (ThreadPoolTaskScheduler) - ctx.getBean( - "threadPoolScheduler_projects/fake project/subscriptions/subscription-name"); + (ThreadPoolTaskScheduler) ctx.getBean( + "threadPoolScheduler_projects/fake project/subscriptions/subscription-name"); assertThat(selectiveScheduler.getThreadNamePrefix()) .isEqualTo( "gcp-pubsub-subscriber-projects/fake project/subscriptions/subscription-name"); @@ -347,17 +339,15 @@ void threadPoolTaskScheduler_selectiveThreadNameConfiguration() { contextRunner .withPropertyValues( "spring.cloud.gcp.pubsub.subscription.subscription-name.executor-threads=7") - .withBean( - SelectiveSchedulerThreadNameProvider.class, + .withBean(SelectiveSchedulerThreadNameProvider.class, () -> subscriptionName -> "custom-" + subscriptionName.getSubscription()) .run( ctx -> { ThreadPoolTaskScheduler selectiveScheduler = - (ThreadPoolTaskScheduler) - ctx.getBean( - "threadPoolScheduler_projects/fake project/subscriptions/subscription-name"); - assertThat(selectiveScheduler.getThreadNamePrefix()) - .isEqualTo("custom-subscription-name"); + (ThreadPoolTaskScheduler) ctx.getBean( + "threadPoolScheduler_projects/fake project/subscriptions/subscription-name"); + assertThat(selectiveScheduler.getThreadNamePrefix()).isEqualTo( + "custom-subscription-name"); }); } @@ -371,9 +361,8 @@ void subscriberExecutorProvider_selectiveConfigurationSet() { DefaultSubscriberFactory factory = (DefaultSubscriberFactory) ctx.getBean("defaultSubscriberFactory"); ExecutorProvider selectiveExecutorProvider = - (ExecutorProvider) - ctx.getBean( - "subscriberExecutorProvider-projects/fake project/subscriptions/subscription-name"); + (ExecutorProvider) ctx.getBean( + "subscriberExecutorProvider-projects/fake project/subscriptions/subscription-name"); assertThat(selectiveExecutorProvider).isNotNull(); assertThat(factory.getExecutorProvider("subscription-name")) .isSameAs(selectiveExecutorProvider); @@ -388,11 +377,11 @@ void threadPoolScheduler_globalAndSelectiveConfigurationSet() { "spring.cloud.gcp.pubsub.subscription.subscription-name.executor-threads=3") .run( ctx -> { + // Verify that selective and global beans have been created ThreadPoolTaskScheduler selectiveScheduler = - (ThreadPoolTaskScheduler) - ctx.getBean( - "threadPoolScheduler_projects/fake project/subscriptions/subscription-name"); + (ThreadPoolTaskScheduler) ctx.getBean( + "threadPoolScheduler_projects/fake project/subscriptions/subscription-name"); assertThat(selectiveScheduler.getThreadNamePrefix()) .isEqualTo( "gcp-pubsub-subscriber-projects/fake project/subscriptions/subscription-name"); @@ -409,8 +398,8 @@ void subscriberExecutorProvider_globalAndDifferentSelectiveConfigurationSet_only "spring.cloud.gcp.pubsub.subscription.subscription-name.parallel-pull-count=3") .run( ctx -> { - assertThat(ctx.containsBean("subscriberExecutorProvider-subscription-name")) - .isFalse(); + assertThat( + ctx.containsBean("subscriberExecutorProvider-subscription-name")).isFalse(); }); } @@ -425,9 +414,8 @@ void subscriberExecutorProvider_globalAndSelectiveConfigurationSet_selectiveTake DefaultSubscriberFactory factory = (DefaultSubscriberFactory) ctx.getBean("defaultSubscriberFactory"); ExecutorProvider selectiveExecutorProvider = - (ExecutorProvider) - ctx.getBean( - "subscriberExecutorProvider-projects/fake project/subscriptions/subscription-name"); + (ExecutorProvider) ctx.getBean( + "subscriberExecutorProvider-projects/fake project/subscriptions/subscription-name"); assertThat(selectiveExecutorProvider).isNotNull(); assertThat(factory.getExecutorProvider("subscription-name")) .isSameAs(selectiveExecutorProvider); @@ -436,31 +424,32 @@ void subscriberExecutorProvider_globalAndSelectiveConfigurationSet_selectiveTake @Test void pullConfig_defaultConfigurationSet() { - contextRunner.run( - ctx -> { - GcpPubSubProperties gcpPubSubProperties = ctx.getBean(GcpPubSubProperties.class); - GcpProjectIdProvider projectIdProvider = ctx.getBean(GcpProjectIdProvider.class); - assertThat( + contextRunner + .run( + ctx -> { + GcpPubSubProperties gcpPubSubProperties = ctx.getBean(GcpPubSubProperties.class); + GcpProjectIdProvider projectIdProvider = ctx.getBean(GcpProjectIdProvider.class); + assertThat( gcpPubSubProperties.computeMaxAckExtensionPeriod( "subscription-name", projectIdProvider.getProjectId())) - .isNull(); - assertThat( + .isNull(); + assertThat( gcpPubSubProperties.computeMinDurationPerAckExtension( "subscription-name", projectIdProvider.getProjectId())) - .isNull(); - assertThat( + .isNull(); + assertThat( gcpPubSubProperties.computeMaxDurationPerAckExtension( "subscription-name", projectIdProvider.getProjectId())) - .isNull(); - assertThat( + .isNull(); + assertThat( gcpPubSubProperties.computeParallelPullCount( "subscription-name", projectIdProvider.getProjectId())) - .isNull(); - assertThat( + .isNull(); + assertThat( gcpPubSubProperties.computePullEndpoint( "subscription-name", projectIdProvider.getProjectId())) - .isNull(); - }); + .isNull(); + }); } @Test @@ -473,9 +462,11 @@ void minOrMaxDurationPerAckExtension_invalidSubscriberConfigurationSet() { ctx -> { DefaultSubscriberFactory factory = (DefaultSubscriberFactory) ctx.getBean("defaultSubscriberFactory"); - assertThatThrownBy( - () -> - factory.createSubscriber("subscription-name", (message, consumer) -> {})) + assertThatThrownBy(() -> + factory.createSubscriber( + "subscription-name", + (message, consumer) -> { + })) .isExactlyInstanceOf(IllegalArgumentException.class); }); } @@ -492,9 +483,11 @@ void minOrMaxDurationPerAckExtension_invalidSubscriptionConfigurationSet() { ctx -> { DefaultSubscriberFactory factory = (DefaultSubscriberFactory) ctx.getBean("defaultSubscriberFactory"); - assertThatThrownBy( - () -> - factory.createSubscriber("subscription-name", (message, consumer) -> {})) + assertThatThrownBy(() -> + factory.createSubscriber( + "subscription-name", + (message, consumer) -> { + })) .isExactlyInstanceOf(IllegalArgumentException.class); }); } @@ -513,27 +506,27 @@ void pullConfig_globalConfigurationSet() { GcpPubSubProperties gcpPubSubProperties = ctx.getBean(GcpPubSubProperties.class); GcpProjectIdProvider projectIdProvider = ctx.getBean(GcpProjectIdProvider.class); assertThat( - gcpPubSubProperties.computeMaxAckExtensionPeriod( - "subscription-name", projectIdProvider.getProjectId())) + gcpPubSubProperties.computeMaxAckExtensionPeriod( + "subscription-name", projectIdProvider.getProjectId())) .isEqualTo(7L); assertThat( - gcpPubSubProperties.computeMinDurationPerAckExtension( - "subscription-name", projectIdProvider.getProjectId())) + gcpPubSubProperties.computeMinDurationPerAckExtension( + "subscription-name", projectIdProvider.getProjectId())) .isEqualTo(3L); assertThat( - gcpPubSubProperties.computeMaxDurationPerAckExtension( - "subscription-name", projectIdProvider.getProjectId())) + gcpPubSubProperties.computeMaxDurationPerAckExtension( + "subscription-name", projectIdProvider.getProjectId())) .isEqualTo(4L); assertThat( - gcpPubSubProperties.computeParallelPullCount( - "subscription-name", projectIdProvider.getProjectId())) + gcpPubSubProperties.computeParallelPullCount( + "subscription-name", projectIdProvider.getProjectId())) .isEqualTo(12); assertThat( - gcpPubSubProperties.computePullEndpoint( - "subscription-name", projectIdProvider.getProjectId())) + gcpPubSubProperties.computePullEndpoint( + "subscription-name", projectIdProvider.getProjectId())) .isEqualTo("my-endpoint"); - assertThat(gcpPubSubProperties.getSubscriber().getMaxAckExtensionPeriod()) - .isEqualTo(7L); + assertThat(gcpPubSubProperties.getSubscriber().getMaxAckExtensionPeriod()).isEqualTo( + 7L); assertThat(gcpPubSubProperties.getSubscriber().getParallelPullCount()).isEqualTo(12); assertThat(gcpPubSubProperties.getSubscriber().getPullEndpoint()) .isEqualTo("my-endpoint"); @@ -554,29 +547,28 @@ void pullConfig_selectiveConfigurationSet() { GcpPubSubProperties gcpPubSubProperties = ctx.getBean(GcpPubSubProperties.class); GcpProjectIdProvider projectIdProvider = ctx.getBean(GcpProjectIdProvider.class); assertThat( - gcpPubSubProperties.computeMaxAckExtensionPeriod( - "subscription-name", projectIdProvider.getProjectId())) + gcpPubSubProperties.computeMaxAckExtensionPeriod( + "subscription-name", projectIdProvider.getProjectId())) .isEqualTo(7L); assertThat( - gcpPubSubProperties.computeMinDurationPerAckExtension( - "subscription-name", projectIdProvider.getProjectId())) + gcpPubSubProperties.computeMinDurationPerAckExtension( + "subscription-name", projectIdProvider.getProjectId())) .isEqualTo(3L); assertThat( - gcpPubSubProperties.computeMaxDurationPerAckExtension( - "subscription-name", projectIdProvider.getProjectId())) + gcpPubSubProperties.computeMaxDurationPerAckExtension( + "subscription-name", projectIdProvider.getProjectId())) .isEqualTo(4L); assertThat( - gcpPubSubProperties.computeParallelPullCount( - "subscription-name", projectIdProvider.getProjectId())) + gcpPubSubProperties.computeParallelPullCount( + "subscription-name", projectIdProvider.getProjectId())) .isEqualTo(12); assertThat( - gcpPubSubProperties.computePullEndpoint( - "subscription-name", projectIdProvider.getProjectId())) + gcpPubSubProperties.computePullEndpoint( + "subscription-name", projectIdProvider.getProjectId())) .isEqualTo("my-endpoint"); assertThat(gcpPubSubProperties.getFullyQualifiedSubscriberProperties()) - .containsKey( - ProjectSubscriptionName.parse( - "projects/fake project/subscriptions/subscription-name")); + .containsKey(ProjectSubscriptionName.parse( + "projects/fake project/subscriptions/subscription-name")); }); } @@ -599,51 +591,50 @@ void pullConfig_globalAndSelectiveConfigurationSet_selectiveTakesPrecedence() { GcpPubSubProperties gcpPubSubProperties = ctx.getBean(GcpPubSubProperties.class); GcpProjectIdProvider projectIdProvider = ctx.getBean(GcpProjectIdProvider.class); assertThat( - gcpPubSubProperties.computeMaxAckExtensionPeriod( - "subscription-name", projectIdProvider.getProjectId())) + gcpPubSubProperties.computeMaxAckExtensionPeriod( + "subscription-name", projectIdProvider.getProjectId())) .isEqualTo(7L); assertThat( - gcpPubSubProperties.computeMinDurationPerAckExtension( - "subscription-name", projectIdProvider.getProjectId())) + gcpPubSubProperties.computeMinDurationPerAckExtension( + "subscription-name", projectIdProvider.getProjectId())) .isEqualTo(5L); assertThat( - gcpPubSubProperties.computeMaxDurationPerAckExtension( - "subscription-name", projectIdProvider.getProjectId())) + gcpPubSubProperties.computeMaxDurationPerAckExtension( + "subscription-name", projectIdProvider.getProjectId())) .isEqualTo(6L); assertThat( - gcpPubSubProperties.computeParallelPullCount( - "subscription-name", projectIdProvider.getProjectId())) + gcpPubSubProperties.computeParallelPullCount( + "subscription-name", projectIdProvider.getProjectId())) .isEqualTo(12); assertThat( - gcpPubSubProperties.computePullEndpoint( - "subscription-name", projectIdProvider.getProjectId())) + gcpPubSubProperties.computePullEndpoint( + "subscription-name", projectIdProvider.getProjectId())) .isEqualTo("my-endpoint"); assertThat( - gcpPubSubProperties.computeMaxAckExtensionPeriod( - "other", projectIdProvider.getProjectId())) + gcpPubSubProperties.computeMaxAckExtensionPeriod( + "other", projectIdProvider.getProjectId())) .isEqualTo(5L); assertThat( - gcpPubSubProperties.computeMinDurationPerAckExtension( - "other", projectIdProvider.getProjectId())) + gcpPubSubProperties.computeMinDurationPerAckExtension( + "other", projectIdProvider.getProjectId())) .isEqualTo(3L); assertThat( - gcpPubSubProperties.computeMaxDurationPerAckExtension( - "other", projectIdProvider.getProjectId())) + gcpPubSubProperties.computeMaxDurationPerAckExtension( + "other", projectIdProvider.getProjectId())) .isEqualTo(4L); assertThat( - gcpPubSubProperties.computeParallelPullCount( - "other", projectIdProvider.getProjectId())) + gcpPubSubProperties.computeParallelPullCount( + "other", projectIdProvider.getProjectId())) .isEqualTo(10); assertThat( - gcpPubSubProperties.computePullEndpoint( - "other", projectIdProvider.getProjectId())) + gcpPubSubProperties.computePullEndpoint( + "other", projectIdProvider.getProjectId())) .isEqualTo("other-endpoint"); assertThat(gcpPubSubProperties.getFullyQualifiedSubscriberProperties()).hasSize(1); assertThat(gcpPubSubProperties.getFullyQualifiedSubscriberProperties()) - .containsKey( - ProjectSubscriptionName.parse( - "projects/fake project/subscriptions/subscription-name")); + .containsKey(ProjectSubscriptionName.parse( + "projects/fake project/subscriptions/subscription-name")); }); } @@ -662,29 +653,28 @@ void pullConfig_globalAndDifferentSelectiveConfigurationSet_pickGlobal() { GcpPubSubProperties gcpPubSubProperties = ctx.getBean(GcpPubSubProperties.class); GcpProjectIdProvider projectIdProvider = ctx.getBean(GcpProjectIdProvider.class); assertThat( - gcpPubSubProperties.computeMaxAckExtensionPeriod( - "subscription-name", projectIdProvider.getProjectId())) + gcpPubSubProperties.computeMaxAckExtensionPeriod( + "subscription-name", projectIdProvider.getProjectId())) .isEqualTo(5); assertThat( - gcpPubSubProperties.computeMinDurationPerAckExtension( - "subscription-name", projectIdProvider.getProjectId())) + gcpPubSubProperties.computeMinDurationPerAckExtension( + "subscription-name", projectIdProvider.getProjectId())) .isEqualTo(3); assertThat( - gcpPubSubProperties.computeMaxDurationPerAckExtension( - "subscription-name", projectIdProvider.getProjectId())) + gcpPubSubProperties.computeMaxDurationPerAckExtension( + "subscription-name", projectIdProvider.getProjectId())) .isEqualTo(4); assertThat( - gcpPubSubProperties.computeParallelPullCount( - "subscription-name", projectIdProvider.getProjectId())) + gcpPubSubProperties.computeParallelPullCount( + "subscription-name", projectIdProvider.getProjectId())) .isEqualTo(10); assertThat( - gcpPubSubProperties.computePullEndpoint( - "subscription-name", projectIdProvider.getProjectId())) + gcpPubSubProperties.computePullEndpoint( + "subscription-name", projectIdProvider.getProjectId())) .isEqualTo("other-endpoint"); assertThat(gcpPubSubProperties.getFullyQualifiedSubscriberProperties()) - .containsKey( - ProjectSubscriptionName.parse( - "projects/fake project/subscriptions/subscription-name")); + .containsKey(ProjectSubscriptionName.parse( + "projects/fake project/subscriptions/subscription-name")); }); } @@ -721,8 +711,7 @@ void retrySettings_globalConfigurationSet() { GcpProjectIdProvider projectIdProvider = ctx.getBean(GcpProjectIdProvider.class); PubSubConfiguration.Retry retrySettings = gcpPubSubProperties.computeSubscriberRetrySettings( - ProjectSubscriptionName.of( - projectIdProvider.getProjectId(), "subscription-name")); + ProjectSubscriptionName.of(projectIdProvider.getProjectId(), "subscription-name")); assertThat(retrySettings.getTotalTimeoutSeconds()).isEqualTo(1L); assertThat(retrySettings.getInitialRetryDelaySeconds()).isEqualTo(2L); assertThat(retrySettings.getRetryDelayMultiplier()).isEqualTo(3); @@ -746,8 +735,8 @@ void retrySettings_globalConfigurationSet() { .setRpcTimeoutMultiplier(7) .setMaxRpcTimeout(Duration.ofSeconds(8)) .build(); - assertThat(subscriberFactory.getRetrySettings("name")) - .isEqualTo(expectedRetrySettings); + assertThat(subscriberFactory.getRetrySettings("name")).isEqualTo( + expectedRetrySettings); assertThat(ctx.getBean("globalSubscriberRetrySettings", RetrySettings.class)) .isEqualTo(expectedRetrySettings); }); @@ -772,8 +761,7 @@ void retrySettings_selectiveConfigurationSet() { GcpProjectIdProvider projectIdProvider = ctx.getBean(GcpProjectIdProvider.class); PubSubConfiguration.Retry retrySettings = gcpPubSubProperties.computeSubscriberRetrySettings( - ProjectSubscriptionName.of( - projectIdProvider.getProjectId(), "subscription-name")); + ProjectSubscriptionName.of(projectIdProvider.getProjectId(), "subscription-name")); assertThat(retrySettings.getTotalTimeoutSeconds()).isEqualTo(1L); assertThat(retrySettings.getInitialRetryDelaySeconds()).isEqualTo(2L); assertThat(retrySettings.getRetryDelayMultiplier()).isEqualTo(3); @@ -785,9 +773,8 @@ void retrySettings_selectiveConfigurationSet() { assertThat(retrySettings.getMaxRpcTimeoutSeconds()).isEqualTo(8); assertThat(gcpPubSubProperties.getFullyQualifiedSubscriberProperties()).hasSize(1); assertThat(gcpPubSubProperties.getFullyQualifiedSubscriberProperties()) - .containsKey( - ProjectSubscriptionName.parse( - "projects/fake project/subscriptions/subscription-name")); + .containsKey(ProjectSubscriptionName.parse( + "projects/fake project/subscriptions/subscription-name")); DefaultSubscriberFactory subscriberFactory = ctx.getBean("defaultSubscriberFactory", DefaultSubscriberFactory.class); @@ -804,10 +791,9 @@ void retrySettings_selectiveConfigurationSet() { .build(); assertThat(subscriberFactory.getRetrySettings("subscription-name")) .isEqualTo(expectedRetrySettings); - assertThat( - ctx.getBean( - "subscriberRetrySettings-projects/fake project/subscriptions/subscription-name", - RetrySettings.class)) + assertThat(ctx.getBean( + "subscriberRetrySettings-projects/fake project/subscriptions/subscription-name", + RetrySettings.class)) .isEqualTo(expectedRetrySettings); }); } @@ -841,12 +827,10 @@ void retrySettings_globalAndSelectiveConfigurationSet_selectiveTakesPrecedence() // property set PubSubConfiguration.Retry retrySettings = gcpPubSubProperties.computeSubscriberRetrySettings( - ProjectSubscriptionName.of( - projectIdProvider.getProjectId(), "subscription-name")); + ProjectSubscriptionName.of(projectIdProvider.getProjectId(), "subscription-name")); assertThat(gcpPubSubProperties.getFullyQualifiedSubscriberProperties()) - .containsKey( - ProjectSubscriptionName.parse( - "projects/fake project/subscriptions/subscription-name")); + .containsKey(ProjectSubscriptionName.parse( + "projects/fake project/subscriptions/subscription-name")); assertThat(retrySettings.getTotalTimeoutSeconds()).isEqualTo(1L); assertThat(retrySettings.getInitialRetryDelaySeconds()).isEqualTo(2L); assertThat(retrySettings.getRetryDelayMultiplier()).isEqualTo(3); @@ -861,25 +845,23 @@ void retrySettings_globalAndSelectiveConfigurationSet_selectiveTakesPrecedence() // property set PubSubConfiguration.Retry retrySettingsForOtherSubscriber = gcpPubSubProperties - .getSubscriptionProperties( - PubSubSubscriptionUtils.toProjectSubscriptionName( - "other", projectIdProvider.getProjectId())) + .getSubscriptionProperties(PubSubSubscriptionUtils + .toProjectSubscriptionName("other", projectIdProvider.getProjectId())) .getRetry(); assertThat(retrySettingsForOtherSubscriber.getTotalTimeoutSeconds()).isEqualTo(10L); - assertThat(retrySettingsForOtherSubscriber.getInitialRetryDelaySeconds()) - .isEqualTo(10L); + assertThat(retrySettingsForOtherSubscriber.getInitialRetryDelaySeconds()).isEqualTo( + 10L); assertThat(retrySettingsForOtherSubscriber.getRetryDelayMultiplier()).isEqualTo(10); assertThat(retrySettingsForOtherSubscriber.getMaxRetryDelaySeconds()).isEqualTo(10); assertThat(retrySettingsForOtherSubscriber.getMaxAttempts()).isEqualTo(10); - assertThat(retrySettingsForOtherSubscriber.getInitialRpcTimeoutSeconds()) - .isEqualTo(10); + assertThat(retrySettingsForOtherSubscriber.getInitialRpcTimeoutSeconds()).isEqualTo( + 10); assertThat(retrySettingsForOtherSubscriber.getRpcTimeoutMultiplier()).isEqualTo(10); assertThat(retrySettingsForOtherSubscriber.getMaxRpcTimeoutSeconds()).isEqualTo(10); assertThat(gcpPubSubProperties.getFullyQualifiedSubscriberProperties()).hasSize(1); assertThat(gcpPubSubProperties.getFullyQualifiedSubscriberProperties()) - .containsKey( - ProjectSubscriptionName.parse( - "projects/fake project/subscriptions/subscription-name")); + .containsKey(ProjectSubscriptionName.parse( + "projects/fake project/subscriptions/subscription-name")); // Verify that beans for selective and global retry settings are created. Also // verify that selective retry setting takes precedence. @@ -909,10 +891,9 @@ void retrySettings_globalAndSelectiveConfigurationSet_selectiveTakesPrecedence() .build(); assertThat(subscriberFactory.getRetrySettings("subscription-name")) .isEqualTo(expectedRetrySettingsForSubscriptionName); - assertThat( - ctx.getBean( - "subscriberRetrySettings-projects/fake project/subscriptions/subscription-name", - RetrySettings.class)) + assertThat(ctx.getBean( + "subscriberRetrySettings-projects/fake project/subscriptions/subscription-name", + RetrySettings.class)) .isEqualTo(expectedRetrySettingsForSubscriptionName); assertThat(subscriberFactory.getRetrySettings("other")) .isEqualTo(expectedRetrySettingsForOther); @@ -941,8 +922,7 @@ void retrySettings_globalAndDifferentSelectiveConfigurationSet_pickGlobal() { PubSubConfiguration.Retry retrySettings = gcpPubSubProperties.computeSubscriberRetrySettings( - ProjectSubscriptionName.of( - projectIdProvider.getProjectId(), "subscription-name")); + ProjectSubscriptionName.of(projectIdProvider.getProjectId(), "subscription-name")); assertThat(retrySettings.getTotalTimeoutSeconds()).isEqualTo(10L); assertThat(retrySettings.getInitialRetryDelaySeconds()).isEqualTo(10L); assertThat(retrySettings.getRetryDelayMultiplier()).isEqualTo(10); @@ -991,8 +971,7 @@ void retrySettings_subsetOfProperties_pickGlobalWhenSelectiveNotSpecified() { GcpProjectIdProvider projectIdProvider = ctx.getBean(GcpProjectIdProvider.class); PubSubConfiguration.Retry retry = gcpPubSubProperties.computeSubscriberRetrySettings( - ProjectSubscriptionName.of( - projectIdProvider.getProjectId(), "subscription-name")); + ProjectSubscriptionName.of(projectIdProvider.getProjectId(), "subscription-name")); assertThat(retry.getTotalTimeoutSeconds()).isEqualTo(10L); assertThat(retry.getInitialRetryDelaySeconds()).isEqualTo(2L); assertThat(retry.getRetryDelayMultiplier()).isEqualTo(3); @@ -1020,10 +999,9 @@ void retrySettings_subsetOfProperties_pickGlobalWhenSelectiveNotSpecified() { RetrySettings.newBuilder().setTotalTimeout(Duration.ofSeconds(10L)).build(); assertThat(subscriberFactory.getRetrySettings("subscription-name")) .isEqualTo(expectedRetrySettingsForSubscriptionName); - assertThat( - ctx.getBean( - "subscriberRetrySettings-projects/fake project/subscriptions/subscription-name", - RetrySettings.class)) + assertThat(ctx.getBean( + "subscriberRetrySettings-projects/fake project/subscriptions/subscription-name", + RetrySettings.class)) .isEqualTo(expectedRetrySettingsForSubscriptionName); assertThat(ctx.getBean("globalSubscriberRetrySettings", RetrySettings.class)) .isEqualTo(expectedGlobalRetrySettings); @@ -1036,7 +1014,9 @@ void customFlowControlUsedWhenProvided() { contextRunner .withBean( - "subscriberFlowControlSettings", FlowControlSettings.class, () -> flowControlSettings) + "subscriberFlowControlSettings", + FlowControlSettings.class, + () -> flowControlSettings) .run( ctx -> { DefaultSubscriberFactory subscriberFactory = @@ -1068,16 +1048,16 @@ void flowControlSettings_globalConfigurationSet() { .setLimitExceededBehavior(FlowController.LimitExceededBehavior.Ignore) .build(); - assertThat(flowControlFromConfiguration.getMaxOutstandingElementCount()) - .isEqualTo(11L); - assertThat(flowControlFromConfiguration.getMaxOutstandingRequestBytes()) - .isEqualTo(12L); + assertThat(flowControlFromConfiguration.getMaxOutstandingElementCount()).isEqualTo( + 11L); + assertThat(flowControlFromConfiguration.getMaxOutstandingRequestBytes()).isEqualTo( + 12L); assertThat(flowControlFromConfiguration.getLimitExceededBehavior()) .isEqualTo(FlowController.LimitExceededBehavior.Ignore); assertThat(subscriberFactory.getFlowControlSettings("name")) .isEqualTo(expectedFlowControlSettings); assertThat( - ctx.getBean("globalSubscriberFlowControlSettings", FlowControlSettings.class)) + ctx.getBean("globalSubscriberFlowControlSettings", FlowControlSettings.class)) .isEqualTo(expectedFlowControlSettings); }); } @@ -1097,8 +1077,8 @@ void flowControlSettings_selectiveConfigurationSet() { PubSubConfiguration.FlowControl flowControl = gcpPubSubProperties .getSubscriptionProperties( - PubSubSubscriptionUtils.toProjectSubscriptionName( - "subscription-name", projectIdProvider.getProjectId())) + PubSubSubscriptionUtils + .toProjectSubscriptionName("subscription-name", projectIdProvider.getProjectId())) .getFlowControl(); assertThat(flowControl.getMaxOutstandingElementCount()).isEqualTo(11L); assertThat(flowControl.getMaxOutstandingRequestBytes()).isEqualTo(12L); @@ -1106,9 +1086,8 @@ void flowControlSettings_selectiveConfigurationSet() { .isEqualTo(FlowController.LimitExceededBehavior.Ignore); assertThat(gcpPubSubProperties.getFullyQualifiedSubscriberProperties()).hasSize(1); assertThat(gcpPubSubProperties.getFullyQualifiedSubscriberProperties()) - .containsKey( - ProjectSubscriptionName.parse( - "projects/fake project/subscriptions/subscription-name")); + .containsKey(ProjectSubscriptionName.parse( + "projects/fake project/subscriptions/subscription-name")); DefaultSubscriberFactory subscriberFactory = ctx.getBean("defaultSubscriberFactory", DefaultSubscriberFactory.class); @@ -1121,9 +1100,9 @@ void flowControlSettings_selectiveConfigurationSet() { assertThat(subscriberFactory.getFlowControlSettings("subscription-name")) .isEqualTo(expectedFlowControlForSubscriptionName); assertThat( - ctx.getBean( - "subscriberFlowControlSettings-projects/fake project/subscriptions/subscription-name", - FlowControlSettings.class)) + ctx.getBean( + "subscriberFlowControlSettings-projects/fake project/subscriptions/subscription-name", + FlowControlSettings.class)) .isEqualTo(expectedFlowControlForSubscriptionName); }); } @@ -1143,36 +1122,33 @@ void flowControlSettings_globalAndSelectiveConfigurationSet_selectiveTakesPreced GcpPubSubProperties gcpPubSubProperties = ctx.getBean(GcpPubSubProperties.class); GcpProjectIdProvider projectIdProvider = ctx.getBean(GcpProjectIdProvider.class); - // Validate settings for subscribers that have subscription-specific flow control - // settings + // Validate settings for subscribers that have subscription-specific flow control settings // property set PubSubConfiguration.FlowControl flowControl = gcpPubSubProperties.computeSubscriberFlowControlSettings( - ProjectSubscriptionName.of( - projectIdProvider.getProjectId(), "subscription-name")); + ProjectSubscriptionName.of(projectIdProvider.getProjectId(), + "subscription-name")); assertThat(flowControl.getMaxOutstandingElementCount()).isEqualTo(11L); assertThat(flowControl.getMaxOutstandingRequestBytes()).isEqualTo(12L); assertThat(flowControl.getLimitExceededBehavior()) .isEqualTo(FlowController.LimitExceededBehavior.Ignore); - // Validate settings for subscribers that do not have subscription-specific flow - // control + // Validate settings for subscribers that do not have subscription-specific flow control // settings property set PubSubConfiguration.FlowControl flowControlForOtherSubscriber = gcpPubSubProperties.computeSubscriberFlowControlSettings( ProjectSubscriptionName.of(projectIdProvider.getProjectId(), "other")); - assertThat(flowControlForOtherSubscriber.getMaxOutstandingElementCount()) - .isEqualTo(10L); - assertThat(flowControlForOtherSubscriber.getMaxOutstandingRequestBytes()) - .isEqualTo(10L); + assertThat(flowControlForOtherSubscriber.getMaxOutstandingElementCount()).isEqualTo( + 10L); + assertThat(flowControlForOtherSubscriber.getMaxOutstandingRequestBytes()).isEqualTo( + 10L); assertThat(flowControlForOtherSubscriber.getLimitExceededBehavior()) .isEqualTo(FlowController.LimitExceededBehavior.Block); // Change in behavior: calculated properties don't get stored assertThat(gcpPubSubProperties.getFullyQualifiedSubscriberProperties()).hasSize(1); assertThat(gcpPubSubProperties.getFullyQualifiedSubscriberProperties()) - .containsKey( - ProjectSubscriptionName.parse( - "projects/fake project/subscriptions/subscription-name")); + .containsKey(ProjectSubscriptionName.parse( + "projects/fake project/subscriptions/subscription-name")); // Verify that beans for selective and global flow control settings are created. DefaultSubscriberFactory subscriberFactory = @@ -1192,14 +1168,14 @@ void flowControlSettings_globalAndSelectiveConfigurationSet_selectiveTakesPreced assertThat(subscriberFactory.getFlowControlSettings("subscription-name")) .isEqualTo(expectedFlowControlForSubscriptionName); assertThat( - ctx.getBean( - "subscriberFlowControlSettings-projects/fake project/subscriptions/subscription-name", - FlowControlSettings.class)) + ctx.getBean( + "subscriberFlowControlSettings-projects/fake project/subscriptions/subscription-name", + FlowControlSettings.class)) .isEqualTo(expectedFlowControlForSubscriptionName); assertThat(subscriberFactory.getFlowControlSettings("other")) .isEqualTo(expectedFlowControlForOther); assertThat( - ctx.getBean("globalSubscriberFlowControlSettings", FlowControlSettings.class)) + ctx.getBean("globalSubscriberFlowControlSettings", FlowControlSettings.class)) .isEqualTo(expectedFlowControlForOther); }); } @@ -1219,17 +1195,16 @@ void flowControlSettings_globalAndDifferentSelectiveConfigurationSet_pickGlobal( PubSubConfiguration.FlowControl flowControl = gcpPubSubProperties.computeSubscriberFlowControlSettings( - ProjectSubscriptionName.of( - projectIdProvider.getProjectId(), "subscription-name")); + ProjectSubscriptionName.of(projectIdProvider.getProjectId(), + "subscription-name")); assertThat(flowControl.getMaxOutstandingElementCount()).isEqualTo(11L); assertThat(flowControl.getMaxOutstandingRequestBytes()).isEqualTo(12L); assertThat(flowControl.getLimitExceededBehavior()) .isEqualTo(FlowController.LimitExceededBehavior.Ignore); assertThat(gcpPubSubProperties.getFullyQualifiedSubscriberProperties()).hasSize(1); assertThat(gcpPubSubProperties.getFullyQualifiedSubscriberProperties()) - .containsKey( - ProjectSubscriptionName.parse( - "projects/fake project/subscriptions/subscription-name")); + .containsKey(ProjectSubscriptionName.parse( + "projects/fake project/subscriptions/subscription-name")); // Verify that bean for global flow control settings is created. DefaultSubscriberFactory subscriberFactory = @@ -1243,7 +1218,7 @@ void flowControlSettings_globalAndDifferentSelectiveConfigurationSet_pickGlobal( assertThat(subscriberFactory.getFlowControlSettings("subscription-name")) .isEqualTo(expectedFlowControlForSubscriptionName); assertThat( - ctx.getBean("globalSubscriberFlowControlSettings", FlowControlSettings.class)) + ctx.getBean("globalSubscriberFlowControlSettings", FlowControlSettings.class)) .isEqualTo(expectedFlowControlForSubscriptionName); }); } @@ -1263,8 +1238,8 @@ void flowControlSettings_subsetOfProperties_pickGlobalWhenSelectiveNotSpecified( PubSubConfiguration.FlowControl flowControl = gcpPubSubProperties.computeSubscriberFlowControlSettings( - ProjectSubscriptionName.of( - projectIdProvider.getProjectId(), "subscription-name")); + ProjectSubscriptionName.of(projectIdProvider.getProjectId(), + "subscription-name")); assertThat(flowControl.getMaxOutstandingElementCount()).isEqualTo(11L); assertThat(flowControl.getMaxOutstandingRequestBytes()).isEqualTo(12L); assertThat(flowControl.getLimitExceededBehavior()) @@ -1284,12 +1259,12 @@ void flowControlSettings_subsetOfProperties_pickGlobalWhenSelectiveNotSpecified( assertThat(subscriberFactory.getFlowControlSettings("subscription-name")) .isEqualTo(expectedFlowControlForSubscriptionName); assertThat( - ctx.getBean( - "subscriberFlowControlSettings-projects/fake project/subscriptions/subscription-name", - FlowControlSettings.class)) + ctx.getBean( + "subscriberFlowControlSettings-projects/fake project/subscriptions/subscription-name", + FlowControlSettings.class)) .isEqualTo(expectedFlowControlForSubscriptionName); assertThat( - ctx.getBean("globalSubscriberFlowControlSettings", FlowControlSettings.class)) + ctx.getBean("globalSubscriberFlowControlSettings", FlowControlSettings.class)) .isEqualTo(expectedGlobalSettings); }); } @@ -1301,7 +1276,8 @@ void createSubscriberStub_flowControlSettings_noPropertiesSet() { DefaultSubscriberFactory subscriberFactory = ctx.getBean("defaultSubscriberFactory", DefaultSubscriberFactory.class); Subscriber subscriber = - subscriberFactory.createSubscriber("subscription-name", (message, consumer) -> {}); + subscriberFactory.createSubscriber("subscription-name", (message, consumer) -> { + }); assertThat(subscriber.getFlowControlSettings()) .isEqualTo(Subscriber.Builder.getDefaultFlowControlSettings()); }); @@ -1311,25 +1287,24 @@ void createSubscriberStub_flowControlSettings_noPropertiesSet() { void createPublisherWithCustomizer() { contextRunner .withUserConfiguration(CustomizerConfig.class) - .run( - ctx -> { - PublisherFactory factory = - ctx.getBean("defaultPublisherFactory", PublisherFactory.class); - - DefaultPublisherFactory defaultFactory = - (DefaultPublisherFactory) ((CachingPublisherFactory) factory).getDelegate(); - List customizers = - (List) - FieldUtils.readField(defaultFactory, "customizers", true); - assertThat(customizers).hasSize(3); - assertThat(customizers.get(0)).isInstanceOf(NoopCustomizer.class); - assertThat(customizers.get(1)).isInstanceOf(NoopCustomizer.class); - // DefaultPublisherFactory applies highest priority last - assertThat(customizers.get(2)).isInstanceOf(BatchingSettingsCustomizer.class); - - Publisher testPublisher = factory.createPublisher("unused"); - assertThat(testPublisher.getBatchingSettings()).isSameAs(TEST_BATCHING_SETTINGS); - }); + .run(ctx -> { + PublisherFactory factory = + ctx.getBean("defaultPublisherFactory", PublisherFactory.class); + + DefaultPublisherFactory defaultFactory = + (DefaultPublisherFactory) ((CachingPublisherFactory) factory).getDelegate(); + List customizers = + (List) FieldUtils.readField(defaultFactory, "customizers", true); + assertThat(customizers) + .hasSize(3); + assertThat(customizers.get(0)).isInstanceOf(NoopCustomizer.class); + assertThat(customizers.get(1)).isInstanceOf(NoopCustomizer.class); + // DefaultPublisherFactory applies highest priority last + assertThat(customizers.get(2)).isInstanceOf(BatchingSettingsCustomizer.class); + + Publisher testPublisher = factory.createPublisher("unused"); + assertThat(testPublisher.getBatchingSettings()).isSameAs(TEST_BATCHING_SETTINGS); + }); } @Test @@ -1344,8 +1319,8 @@ void flowControlSettings_multipleKeysForSameSubscription_firstOneUsed(CapturedOu GcpPubSubProperties gcpPubSubProperties = ctx.getBean(GcpPubSubProperties.class); GcpProjectIdProvider projectIdProvider = ctx.getBean(GcpProjectIdProvider.class); - ProjectSubscriptionName projectSubscriptionName = - ProjectSubscriptionName.of(projectIdProvider.getProjectId(), "subscription-name"); + ProjectSubscriptionName projectSubscriptionName = ProjectSubscriptionName.of( + projectIdProvider.getProjectId(), "subscription-name"); PubSubConfiguration.FlowControl flowControl = gcpPubSubProperties .getSubscriptionProperties(projectSubscriptionName) @@ -1354,16 +1329,11 @@ void flowControlSettings_multipleKeysForSameSubscription_firstOneUsed(CapturedOu assertThat(gcpPubSubProperties.getFullyQualifiedSubscriberProperties()) .hasSize(1) .containsKey(projectSubscriptionName); - assertThat( - gcpPubSubProperties - .getFullyQualifiedSubscriberProperties() - .get(projectSubscriptionName) - .getFlowControl() - .getMaxOutstandingElementCount()) - .isEqualTo(100L); - assertThat(output) - .contains( - "Found multiple configurations for projects/fake project/subscriptions/subscription-name; ignoring properties with key synthetic-sub-name"); + assertThat(gcpPubSubProperties.getFullyQualifiedSubscriberProperties() + .get(projectSubscriptionName).getFlowControl() + .getMaxOutstandingElementCount()).isEqualTo(100L); + assertThat(output).contains( + "Found multiple configurations for projects/fake project/subscriptions/subscription-name; ignoring properties with key synthetic-sub-name"); }); } @@ -1436,6 +1406,7 @@ BatchingSettingsCustomizer batchingSettingsCustomizer() { NoopCustomizer noop2() { return new NoopCustomizer(); } + } static class NoopCustomizer implements PublisherCustomizer { diff --git a/spring-cloud-gcp-autoconfigure/src/test/java/com/google/cloud/spring/autoconfigure/pubsub/it/PubSubAutoConfigurationIntegrationTests.java b/spring-cloud-gcp-autoconfigure/src/test/java/com/google/cloud/spring/autoconfigure/pubsub/it/PubSubAutoConfigurationIntegrationTests.java index a1cf381e15..d05d3214f1 100644 --- a/spring-cloud-gcp-autoconfigure/src/test/java/com/google/cloud/spring/autoconfigure/pubsub/it/PubSubAutoConfigurationIntegrationTests.java +++ b/spring-cloud-gcp-autoconfigure/src/test/java/com/google/cloud/spring/autoconfigure/pubsub/it/PubSubAutoConfigurationIntegrationTests.java @@ -56,18 +56,15 @@ class PubSubAutoConfigurationIntegrationTests { private static GcpProjectIdProvider projectIdProvider; - private final String fullSubscriptionNameSub1 = - "projects/" + projectIdProvider.getProjectId() + "/subscriptions/" + PULL_SUB; - private final String fullSubscriptionNameSub2 = - "projects/" + projectIdProvider.getProjectId() + "/subscriptions/" + SUBSCRIBE_SUB; + private final String fullSubscriptionNameSub1 = "projects/" + projectIdProvider.getProjectId() + "/subscriptions/" + PULL_SUB; + private final String fullSubscriptionNameSub2 = "projects/" + projectIdProvider.getProjectId() + "/subscriptions/" + SUBSCRIBE_SUB; private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() .withPropertyValues( "spring.cloud.gcp.pubsub.subscriber.retryableCodes=INTERNAL", "spring.cloud.gcp.pubsub.subscription.fully-qualified-test-sub-1-with-project-abc.executor-threads=3", - "spring.cloud.gcp.pubsub.subscription.fully-qualified-test-sub-1-with-project-abc.fully-qualified-name=" - + fullSubscriptionNameSub1, + "spring.cloud.gcp.pubsub.subscription.fully-qualified-test-sub-1-with-project-abc.fully-qualified-name=" + fullSubscriptionNameSub1, "spring.cloud.gcp.pubsub.subscription.fully-qualified-test-sub-1-with-project-abc.retry.total-timeout-seconds=600", "spring.cloud.gcp.pubsub.subscription.fully-qualified-test-sub-1-with-project-abc.retry.initial-retry-delay-seconds=100", "spring.cloud.gcp.pubsub.subscription.fully-qualified-test-sub-1-with-project-abc.retry.retry-delay-multiplier=1.3", @@ -78,28 +75,14 @@ class PubSubAutoConfigurationIntegrationTests { "spring.cloud.gcp.pubsub.subscription.fully-qualified-test-sub-1-with-project-abc.retry.max-rpc-timeout-seconds=600", "spring.cloud.gcp.pubsub.subscription.fully-qualified-test-sub-1-with-project-abc.pull-endpoint=northamerica-northeast2-pubsub.googleapis.com:443", "spring.cloud.gcp.pubsub.subscription." + SUBSCRIBE_SUB + ".executor-threads=1", - "spring.cloud.gcp.pubsub.subscription." - + SUBSCRIBE_SUB - + ".max-ack-extension-period=0", - "spring.cloud.gcp.pubsub.subscription." - + SUBSCRIBE_SUB - + ".min-duration-per-ack-extension=1", - "spring.cloud.gcp.pubsub.subscription." - + SUBSCRIBE_SUB - + ".max-duration-per-ack-extension=2", + "spring.cloud.gcp.pubsub.subscription." + SUBSCRIBE_SUB + ".max-ack-extension-period=0", + "spring.cloud.gcp.pubsub.subscription." + SUBSCRIBE_SUB + ".min-duration-per-ack-extension=1", + "spring.cloud.gcp.pubsub.subscription." + SUBSCRIBE_SUB + ".max-duration-per-ack-extension=2", "spring.cloud.gcp.pubsub.subscription." + SUBSCRIBE_SUB + ".parallel-pull-count=1", - "spring.cloud.gcp.pubsub.subscription." - + SUBSCRIBE_SUB - + ".flow-control.max-outstanding-element-Count=1", - "spring.cloud.gcp.pubsub.subscription." - + SUBSCRIBE_SUB - + ".flow-control.max-outstanding-request-Bytes=1", - "spring.cloud.gcp.pubsub.subscription." - + SUBSCRIBE_SUB - + ".flow-control.limit-exceeded-behavior=Ignore", - "spring.cloud.gcp.pubsub.subscription." - + SUBSCRIBE_SUB - + ".pull-endpoint=bad.endpoint") + "spring.cloud.gcp.pubsub.subscription." + SUBSCRIBE_SUB + ".flow-control.max-outstanding-element-Count=1", + "spring.cloud.gcp.pubsub.subscription." + SUBSCRIBE_SUB + ".flow-control.max-outstanding-request-Bytes=1", + "spring.cloud.gcp.pubsub.subscription." + SUBSCRIBE_SUB + ".flow-control.limit-exceeded-behavior=Ignore", + "spring.cloud.gcp.pubsub.subscription." + SUBSCRIBE_SUB + ".pull-endpoint=bad.endpoint") .withConfiguration( AutoConfigurations.of( GcpContextAutoConfiguration.class, GcpPubSubAutoConfiguration.class)); @@ -154,25 +137,23 @@ void testPull() { assertThat(retry.getRpcTimeoutMultiplier()).isEqualTo(1); assertThat(retry.getMaxRpcTimeoutSeconds()).isEqualTo(600L); ThreadPoolTaskScheduler scheduler = - (ThreadPoolTaskScheduler) - context.getBean("threadPoolScheduler_" + fullSubscriptionNameSub1); + (ThreadPoolTaskScheduler) context.getBean( + "threadPoolScheduler_" + fullSubscriptionNameSub1); assertThat(scheduler).isNotNull(); - assertThat(scheduler.getThreadNamePrefix()) - .isEqualTo("gcp-pubsub-subscriber-" + fullSubscriptionNameSub1); + assertThat(scheduler.getThreadNamePrefix()).isEqualTo( + "gcp-pubsub-subscriber-" + fullSubscriptionNameSub1); assertThat(scheduler.isDaemon()).isTrue(); - assertThat( - (ExecutorProvider) - context.getBean("subscriberExecutorProvider-" + fullSubscriptionNameSub1)) + assertThat((ExecutorProvider) context.getBean( + "subscriberExecutorProvider-" + fullSubscriptionNameSub1)) .isNotNull(); assertThat(gcpPubSubProperties.computeRetryableCodes(subscriptionName, projectId)) - .isEqualTo(new Code[] {Code.INTERNAL}); + .isEqualTo(new Code[]{Code.INTERNAL}); assertThat(gcpPubSubProperties.computePullEndpoint(fullSubscriptionNameSub1, projectId)) .isEqualTo("northamerica-northeast2-pubsub.googleapis.com:443"); assertThat(gcpPubSubProperties.computePullEndpoint(SUBSCRIBE_SUB, projectId)) .isEqualTo("bad.endpoint"); - assertThat( - (RetrySettings) - context.getBean("subscriberRetrySettings-" + fullSubscriptionNameSub1)) + assertThat((RetrySettings) context.getBean( + "subscriberRetrySettings-" + fullSubscriptionNameSub1)) .isEqualTo(expectedRetrySettings); } finally { pubSubAdmin.deleteSubscription(subscriptionName); @@ -185,6 +166,7 @@ void testPull() { void testSubscribe() { this.contextRunner.run( context -> { + PubSubAdmin pubSubAdmin = context.getBean(PubSubAdmin.class); PubSubTemplate pubSubTemplate = context.getBean(PubSubTemplate.class); @@ -222,37 +204,38 @@ void testSubscribe() { .setLimitExceededBehavior(FlowController.LimitExceededBehavior.Ignore) .build(); assertThat( - (FlowControlSettings) - context.getBean( - "subscriberFlowControlSettings-" + fullSubscriptionNameSub2)) + (FlowControlSettings) context.getBean( + "subscriberFlowControlSettings-" + fullSubscriptionNameSub2)) .isEqualTo(flowControlSettings); assertThat(flowControl.getMaxOutstandingElementCount()).isEqualTo(1L); assertThat(flowControl.getMaxOutstandingRequestBytes()).isEqualTo(1L); assertThat(flowControl.getLimitExceededBehavior()) .isEqualTo(FlowController.LimitExceededBehavior.Ignore); assertThat( - gcpPubSubProperties.computeMaxAckExtensionPeriod(subscriptionName, projectId)) + gcpPubSubProperties.computeMaxAckExtensionPeriod( + subscriptionName, projectId)) .isZero(); assertThat( - gcpPubSubProperties.computeMinDurationPerAckExtension( - subscriptionName, projectId)) + gcpPubSubProperties.computeMinDurationPerAckExtension( + subscriptionName, projectId)) .isEqualTo(1L); assertThat( - gcpPubSubProperties.computeMaxDurationPerAckExtension( - subscriptionName, projectId)) + gcpPubSubProperties.computeMaxDurationPerAckExtension( + subscriptionName, projectId)) .isEqualTo(2L); - assertThat(gcpPubSubProperties.computeParallelPullCount(subscriptionName, projectId)) + assertThat( + gcpPubSubProperties.computeParallelPullCount( + subscriptionName, projectId)) .isEqualTo(1); ThreadPoolTaskScheduler scheduler = - (ThreadPoolTaskScheduler) - context.getBean("threadPoolScheduler_" + fullSubscriptionNameSub2); + (ThreadPoolTaskScheduler) context.getBean( + "threadPoolScheduler_" + fullSubscriptionNameSub2); assertThat(scheduler).isNotNull(); - assertThat(scheduler.getThreadNamePrefix()) - .isEqualTo("gcp-pubsub-subscriber-" + fullSubscriptionNameSub2); + assertThat(scheduler.getThreadNamePrefix()).isEqualTo( + "gcp-pubsub-subscriber-" + fullSubscriptionNameSub2); assertThat(scheduler.isDaemon()).isTrue(); - assertThat( - (ExecutorProvider) - context.getBean("subscriberExecutorProvider-" + fullSubscriptionNameSub2)) + assertThat((ExecutorProvider) context.getBean( + "subscriberExecutorProvider-" + fullSubscriptionNameSub2)) .isNotNull(); } finally { pubSubAdmin.deleteSubscription(subscriptionName); diff --git a/spring-cloud-gcp-pubsub/src/main/java/com/google/cloud/spring/pubsub/support/DefaultSubscriberFactory.java b/spring-cloud-gcp-pubsub/src/main/java/com/google/cloud/spring/pubsub/support/DefaultSubscriberFactory.java index 41b020728f..689ec72abb 100644 --- a/spring-cloud-gcp-pubsub/src/main/java/com/google/cloud/spring/pubsub/support/DefaultSubscriberFactory.java +++ b/spring-cloud-gcp-pubsub/src/main/java/com/google/cloud/spring/pubsub/support/DefaultSubscriberFactory.java @@ -89,8 +89,7 @@ public class DefaultSubscriberFactory implements SubscriberFactory { private RetrySettings globalRetrySettings; - private Map executorProviderMap = - new ConcurrentHashMap<>(); + private Map executorProviderMap = new ConcurrentHashMap<>(); private Code[] retryableCodes; @@ -306,6 +305,7 @@ public Subscriber createSubscriber(String subscriptionName, MessageReceiver rece subscriberBuilder.setUniverseDomain(universeDomain); } + Subscriber subscriber = subscriberBuilder.build(); if (shouldAddToHealthCheck) { @@ -496,8 +496,7 @@ Duration getMaxAckExtensionPeriod(String subscriptionName) { if (this.maxAckExtensionPeriod != null) { return this.maxAckExtensionPeriod; } - Long maxAckExtensionPeriod = - this.pubSubConfiguration.computeMaxAckExtensionPeriod(subscriptionName, projectId); + Long maxAckExtensionPeriod = this.pubSubConfiguration.computeMaxAckExtensionPeriod(subscriptionName, projectId); if (maxAckExtensionPeriod != null) { return Duration.ofSeconds(maxAckExtensionPeriod); } @@ -573,8 +572,7 @@ String getUniverseDomain(String subscriptionName) { return this.pubSubConfiguration.computeSubscriberUniverseDomain(subscriptionName, projectId); } - public void setExecutorProviderMap( - Map executorProviderMap) { + public void setExecutorProviderMap(Map executorProviderMap) { this.executorProviderMap = executorProviderMap; } From a928281768817688df67b2e6538e41ba96a543d5 Mon Sep 17 00:00:00 2001 From: Diego Alonso Marquez Palacios Date: Mon, 3 Feb 2025 09:42:54 -0500 Subject: [PATCH 07/11] reset executor thread changes --- .../pubsub/GcpPubSubAutoConfiguration.java | 25 +++- .../GcpPubSubAutoConfigurationTests.java | 107 +++++++++++++++--- .../support/DefaultSubscriberFactory.java | 22 ++-- 3 files changed, 127 insertions(+), 27 deletions(-) diff --git a/spring-cloud-gcp-autoconfigure/src/main/java/com/google/cloud/spring/autoconfigure/pubsub/GcpPubSubAutoConfiguration.java b/spring-cloud-gcp-autoconfigure/src/main/java/com/google/cloud/spring/autoconfigure/pubsub/GcpPubSubAutoConfiguration.java index 83cc15164a..d8c3d30162 100644 --- a/spring-cloud-gcp-autoconfigure/src/main/java/com/google/cloud/spring/autoconfigure/pubsub/GcpPubSubAutoConfiguration.java +++ b/spring-cloud-gcp-autoconfigure/src/main/java/com/google/cloud/spring/autoconfigure/pubsub/GcpPubSubAutoConfiguration.java @@ -111,10 +111,14 @@ public class GcpPubSubAutoConfiguration { private final ApplicationContext applicationContext; + private ThreadPoolTaskScheduler globalScheduler; + private FlowControlSettings globalFlowControlSettings; private RetrySettings globalRetrySettings; + private ExecutorProvider globalExecutorProvider; + private ObjectProvider selectiveSchedulerThreadNameProvider; public GcpPubSubAutoConfiguration( @@ -253,6 +257,7 @@ public SubscriberFactory defaultSubscriberFactory( factory.setExecutorProvider(executorProvider.get()); } factory.setExecutorProviderMap(this.executorProviderMap); + factory.setGlobalExecutorProvider(this.globalExecutorProvider); factory.setCredentialsProvider(this.finalCredentialsProvider); factory.setHeaderProvider(this.headerProvider); @@ -459,6 +464,13 @@ public void registerSubscriberSettings() { } private void registerSubscriberThreadPoolSchedulerBeans(GenericApplicationContext context) { + Integer numThreads = getGlobalExecutorThreads(); + this.globalScheduler = + createAndRegisterSchedulerBean( + numThreads, + "global-gcp-pubsub-subscriber", + "globalPubSubSubscriberThreadPoolScheduler", + context); registerSelectiveSchedulerBeans(context); } @@ -482,6 +494,11 @@ private void registerExecutorProviderBeans(GenericApplicationContext context) { if (context.containsBean("subscriberExecutorProvider")) { return; } + if (this.globalScheduler != null) { + this.globalExecutorProvider = + createAndRegisterExecutorProvider( + "globalSubscriberExecutorProvider", this.globalScheduler, context); + } createAndRegisterSelectiveExecutorProvider(context); } @@ -542,11 +559,10 @@ private ThreadPoolTaskScheduler createAndRegisterSchedulerBean( String threadName, String beanName, GenericApplicationContext context) { - ThreadPoolTaskScheduler scheduler; - scheduler = executorThreads == null ? null : createThreadPoolTaskScheduler(executorThreads, threadName); + ThreadPoolTaskScheduler scheduler = createThreadPoolTaskScheduler(executorThreads, threadName); context.registerBeanDefinition( beanName, - BeanDefinitionBuilder.genericBeanDefinition(ThreadPoolTaskScheduler.class, () -> scheduler) + BeanDefinitionBuilder.genericBeanDefinition(ThreadPoolTaskScheduler.class, () -> scheduler) .getBeanDefinition()); return scheduler; } @@ -644,6 +660,7 @@ private void createAndRegisterSelectiveRetrySettings(GenericApplicationContext c } private Integer getGlobalExecutorThreads() { - return this.gcpPubSubProperties.getSubscriber().getExecutorThreads(); + Integer numThreads = this.gcpPubSubProperties.getSubscriber().getExecutorThreads(); + return numThreads != null ? numThreads : PubSubConfiguration.DEFAULT_EXECUTOR_THREADS; } } diff --git a/spring-cloud-gcp-autoconfigure/src/test/java/com/google/cloud/spring/autoconfigure/pubsub/GcpPubSubAutoConfigurationTests.java b/spring-cloud-gcp-autoconfigure/src/test/java/com/google/cloud/spring/autoconfigure/pubsub/GcpPubSubAutoConfigurationTests.java index 4b4dddf0d3..3c82a21772 100644 --- a/spring-cloud-gcp-autoconfigure/src/test/java/com/google/cloud/spring/autoconfigure/pubsub/GcpPubSubAutoConfigurationTests.java +++ b/spring-cloud-gcp-autoconfigure/src/test/java/com/google/cloud/spring/autoconfigure/pubsub/GcpPubSubAutoConfigurationTests.java @@ -25,7 +25,6 @@ import com.google.api.gax.batching.FlowController; import com.google.api.gax.core.CredentialsProvider; import com.google.api.gax.core.ExecutorProvider; -import com.google.api.gax.core.InstantiatingExecutorProvider; import com.google.api.gax.grpc.InstantiatingGrpcChannelProvider; import com.google.api.gax.retrying.RetrySettings; import com.google.api.gax.rpc.StatusCode.Code; @@ -145,20 +144,6 @@ void maxInboundMetadataSize_default() { }); } - @Test - void defaultSubscriberFactory_noExecutorThreadsSet_usesClientDefault() { - contextRunner.run( - ctx -> { - DefaultSubscriberFactory defaultSubscriberFactory = - ctx.getBean("defaultSubscriberFactory", DefaultSubscriberFactory.class); - Subscriber subscriber = defaultSubscriberFactory.createSubscriber("dead10cc", (message, consumer) -> {}); - // we confirm that the created subscriber uses the default thread setting in the client (5 as of Jan 2025). - InstantiatingExecutorProvider executorProvider = (InstantiatingExecutorProvider) FieldUtils.readField(subscriber, "executorProvider", true); - Integer threadsPerChannel = (Integer) FieldUtils.readField(subscriber, "THREADS_PER_CHANNEL", true); - assertThat(executorProvider.getExecutorThreadCount()).isEqualTo(threadsPerChannel); - }); - } - @Test void retryableCodes_default() { contextRunner.run( @@ -298,10 +283,25 @@ void customExecutorProviderUsedWhenProvided() { DefaultSubscriberFactory factory = ctx.getBean("defaultSubscriberFactory", DefaultSubscriberFactory.class); assertThat(factory.getExecutorProvider("name")).isSameAs(executorProvider); + assertThat(ctx.containsBean("globalSubscriberExecutorProvider")).isFalse(); assertThat(ctx.containsBean("subscriberExecutorProvider-name")).isFalse(); }); } + @Test + void threadPoolScheduler_noConfigurationSet_globalCreated() { + contextRunner.run( + ctx -> { + ThreadPoolTaskScheduler globalSchedulerBean = + (ThreadPoolTaskScheduler) ctx.getBean("globalPubSubSubscriberThreadPoolScheduler"); + + assertThat(FieldUtils.readField(globalSchedulerBean, "poolSize", true)).isEqualTo(4); + assertThat(globalSchedulerBean.getThreadNamePrefix()) + .isEqualTo("global-gcp-pubsub-subscriber"); + assertThat(globalSchedulerBean.isDaemon()).isTrue(); + }); + } + @Test void subscriberThreadPoolTaskScheduler_globalConfigurationSet() { contextRunner @@ -309,10 +309,33 @@ void subscriberThreadPoolTaskScheduler_globalConfigurationSet() { .run( ctx -> { GcpPubSubProperties gcpPubSubProperties = ctx.getBean(GcpPubSubProperties.class); + ThreadPoolTaskScheduler globalSchedulerBean = + (ThreadPoolTaskScheduler) ctx.getBean( + "globalPubSubSubscriberThreadPoolScheduler"); + assertThat(gcpPubSubProperties.getSubscriber().getExecutorThreads()).isEqualTo(7); + assertThat(globalSchedulerBean.getThreadNamePrefix()) + .isEqualTo("global-gcp-pubsub-subscriber"); + assertThat(FieldUtils.readField(globalSchedulerBean, "poolSize", true)).isEqualTo(7); + assertThat(globalSchedulerBean.isDaemon()).isTrue(); }); } + @Test + void subscriberExecutorProvider_globalConfigurationSet() { + contextRunner + .withPropertyValues("spring.cloud.gcp.pubsub.subscriber.executor-threads=7") + .run( + ctx -> { + DefaultSubscriberFactory factory = + (DefaultSubscriberFactory) ctx.getBean("defaultSubscriberFactory"); + ExecutorProvider globalExecutorProvider = + (ExecutorProvider) ctx.getBean("globalSubscriberExecutorProvider"); + + assertThat(globalExecutorProvider).isNotNull(); + assertThat(factory.getExecutorProvider("other")).isSameAs(globalExecutorProvider); + }); + } @Test void threadPoolTaskScheduler_selectiveConfigurationSet() { @@ -326,11 +349,18 @@ void threadPoolTaskScheduler_selectiveConfigurationSet() { ThreadPoolTaskScheduler selectiveScheduler = (ThreadPoolTaskScheduler) ctx.getBean( "threadPoolScheduler_projects/fake project/subscriptions/subscription-name"); + ThreadPoolTaskScheduler globalScheduler = + (ThreadPoolTaskScheduler) ctx.getBean( + "globalPubSubSubscriberThreadPoolScheduler"); assertThat(selectiveScheduler.getThreadNamePrefix()) .isEqualTo( "gcp-pubsub-subscriber-projects/fake project/subscriptions/subscription-name"); assertThat(selectiveScheduler.isDaemon()).isTrue(); assertThat(FieldUtils.readField(selectiveScheduler, "poolSize", true)).isEqualTo(7); + assertThat(globalScheduler.getThreadNamePrefix()) + .isEqualTo("global-gcp-pubsub-subscriber"); + assertThat(FieldUtils.readField(globalScheduler, "poolSize", true)).isEqualTo(4); + assertThat(globalScheduler.isDaemon()).isTrue(); }); } @@ -363,6 +393,10 @@ void subscriberExecutorProvider_selectiveConfigurationSet() { ExecutorProvider selectiveExecutorProvider = (ExecutorProvider) ctx.getBean( "subscriberExecutorProvider-projects/fake project/subscriptions/subscription-name"); + ExecutorProvider globalExecutorProvider = + (ExecutorProvider) ctx.getBean("globalSubscriberExecutorProvider"); + + assertThat(globalExecutorProvider).isNotNull(); assertThat(selectiveExecutorProvider).isNotNull(); assertThat(factory.getExecutorProvider("subscription-name")) .isSameAs(selectiveExecutorProvider); @@ -382,11 +416,40 @@ void threadPoolScheduler_globalAndSelectiveConfigurationSet() { ThreadPoolTaskScheduler selectiveScheduler = (ThreadPoolTaskScheduler) ctx.getBean( "threadPoolScheduler_projects/fake project/subscriptions/subscription-name"); + ThreadPoolTaskScheduler globalScheduler = + (ThreadPoolTaskScheduler) ctx.getBean( + "globalPubSubSubscriberThreadPoolScheduler"); assertThat(selectiveScheduler.getThreadNamePrefix()) .isEqualTo( "gcp-pubsub-subscriber-projects/fake project/subscriptions/subscription-name"); assertThat(FieldUtils.readField(selectiveScheduler, "poolSize", true)).isEqualTo(3); assertThat(selectiveScheduler.isDaemon()).isTrue(); + assertThat(globalScheduler.getThreadNamePrefix()) + .isEqualTo("global-gcp-pubsub-subscriber"); + assertThat(FieldUtils.readField(globalScheduler, "poolSize", true)).isEqualTo(5); + assertThat(globalScheduler.isDaemon()).isTrue(); + }); + } + + @Test + void threadPoolTaskScheduler_globalAndDifferentSelectiveConfigurationSet_onlyGlobalCreated() { + contextRunner + .withPropertyValues( + "spring.cloud.gcp.pubsub.subscriber.executor-threads=5", + "spring.cloud.gcp.pubsub.subscription.subscription-name.parallel-pull-count=3") + .run( + ctx -> { + + // Verify that only global thread pool task scheduler is created + ThreadPoolTaskScheduler globalScheduler = + (ThreadPoolTaskScheduler) ctx.getBean( + "globalPubSubSubscriberThreadPoolScheduler"); + + assertThat(globalScheduler.getThreadNamePrefix()) + .isEqualTo("global-gcp-pubsub-subscriber"); + assertThat(globalScheduler.isDaemon()).isTrue(); + assertThat(FieldUtils.readField(globalScheduler, "poolSize", true)).isEqualTo(5); + assertThat(ctx.containsBean("threadPoolScheduler_subscription-name")).isFalse(); }); } @@ -398,8 +461,15 @@ void subscriberExecutorProvider_globalAndDifferentSelectiveConfigurationSet_only "spring.cloud.gcp.pubsub.subscription.subscription-name.parallel-pull-count=3") .run( ctx -> { + DefaultSubscriberFactory factory = + (DefaultSubscriberFactory) ctx.getBean("defaultSubscriberFactory"); + + // Verify that global executor provider is created and used + ExecutorProvider globalExecutorProvider = + (ExecutorProvider) ctx.getBean("globalSubscriberExecutorProvider"); assertThat( ctx.containsBean("subscriberExecutorProvider-subscription-name")).isFalse(); + assertThat(factory.getGlobalExecutorProvider()).isSameAs(globalExecutorProvider); }); } @@ -416,7 +486,12 @@ void subscriberExecutorProvider_globalAndSelectiveConfigurationSet_selectiveTake ExecutorProvider selectiveExecutorProvider = (ExecutorProvider) ctx.getBean( "subscriberExecutorProvider-projects/fake project/subscriptions/subscription-name"); + ExecutorProvider globalExecutorProvider = + (ExecutorProvider) ctx.getBean("globalSubscriberExecutorProvider"); + assertThat(selectiveExecutorProvider).isNotNull(); + assertThat(globalExecutorProvider).isNotNull(); + assertThat(factory.getGlobalExecutorProvider()).isNotNull(); assertThat(factory.getExecutorProvider("subscription-name")) .isSameAs(selectiveExecutorProvider); }); @@ -432,7 +507,7 @@ void pullConfig_defaultConfigurationSet() { assertThat( gcpPubSubProperties.computeMaxAckExtensionPeriod( "subscription-name", projectIdProvider.getProjectId())) - .isNull(); + .isZero(); assertThat( gcpPubSubProperties.computeMinDurationPerAckExtension( "subscription-name", projectIdProvider.getProjectId())) diff --git a/spring-cloud-gcp-pubsub/src/main/java/com/google/cloud/spring/pubsub/support/DefaultSubscriberFactory.java b/spring-cloud-gcp-pubsub/src/main/java/com/google/cloud/spring/pubsub/support/DefaultSubscriberFactory.java index 689ec72abb..1ba9347b97 100644 --- a/spring-cloud-gcp-pubsub/src/main/java/com/google/cloud/spring/pubsub/support/DefaultSubscriberFactory.java +++ b/spring-cloud-gcp-pubsub/src/main/java/com/google/cloud/spring/pubsub/support/DefaultSubscriberFactory.java @@ -91,6 +91,8 @@ public class DefaultSubscriberFactory implements SubscriberFactory { private Map executorProviderMap = new ConcurrentHashMap<>(); + private ExecutorProvider globalExecutorProvider; + private Code[] retryableCodes; /** @@ -360,7 +362,8 @@ SubscriberStubSettings buildGlobalSubscriberStubSettings() throws IOException { subscriberStubSettings.setEndpoint(endpoint); } - ExecutorProvider executor = this.executorProvider; + ExecutorProvider executor = + this.executorProvider != null ? this.executorProvider : this.globalExecutorProvider; if (executor != null) { subscriberStubSettings.setBackgroundExecutorProvider(executor); } @@ -449,7 +452,7 @@ public ExecutorProvider getExecutorProvider(String subscriptionName) { if (this.executorProviderMap.containsKey(projectSubscriptionName)) { return this.executorProviderMap.get(projectSubscriptionName); } - return null; + return this.globalExecutorProvider; } /** @@ -496,11 +499,8 @@ Duration getMaxAckExtensionPeriod(String subscriptionName) { if (this.maxAckExtensionPeriod != null) { return this.maxAckExtensionPeriod; } - Long maxAckExtensionPeriod = this.pubSubConfiguration.computeMaxAckExtensionPeriod(subscriptionName, projectId); - if (maxAckExtensionPeriod != null) { - return Duration.ofSeconds(maxAckExtensionPeriod); - } - return null; + return Duration.ofSeconds( + this.pubSubConfiguration.computeMaxAckExtensionPeriod(subscriptionName, projectId)); } @Nullable @@ -576,6 +576,14 @@ public void setExecutorProviderMap(Map flowControlSettingsMap) { this.flowControlSettingsMap = flowControlSettingsMap; From 44d336a71937636333c2e07bb47e700b6397ee6c Mon Sep 17 00:00:00 2001 From: Diego Alonso Marquez Palacios Date: Mon, 3 Feb 2025 09:43:54 -0500 Subject: [PATCH 08/11] reset ITs --- .../it/PubSubAutoConfigurationIntegrationTests.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/spring-cloud-gcp-autoconfigure/src/test/java/com/google/cloud/spring/autoconfigure/pubsub/it/PubSubAutoConfigurationIntegrationTests.java b/spring-cloud-gcp-autoconfigure/src/test/java/com/google/cloud/spring/autoconfigure/pubsub/it/PubSubAutoConfigurationIntegrationTests.java index d05d3214f1..0431941016 100644 --- a/spring-cloud-gcp-autoconfigure/src/test/java/com/google/cloud/spring/autoconfigure/pubsub/it/PubSubAutoConfigurationIntegrationTests.java +++ b/spring-cloud-gcp-autoconfigure/src/test/java/com/google/cloud/spring/autoconfigure/pubsub/it/PubSubAutoConfigurationIntegrationTests.java @@ -143,9 +143,15 @@ void testPull() { assertThat(scheduler.getThreadNamePrefix()).isEqualTo( "gcp-pubsub-subscriber-" + fullSubscriptionNameSub1); assertThat(scheduler.isDaemon()).isTrue(); + assertThat( + (ThreadPoolTaskScheduler) + context.getBean("globalPubSubSubscriberThreadPoolScheduler")) + .isNotNull(); assertThat((ExecutorProvider) context.getBean( "subscriberExecutorProvider-" + fullSubscriptionNameSub1)) .isNotNull(); + assertThat((ExecutorProvider) context.getBean("globalSubscriberExecutorProvider")) + .isNotNull(); assertThat(gcpPubSubProperties.computeRetryableCodes(subscriptionName, projectId)) .isEqualTo(new Code[]{Code.INTERNAL}); assertThat(gcpPubSubProperties.computePullEndpoint(fullSubscriptionNameSub1, projectId)) @@ -234,9 +240,15 @@ void testSubscribe() { assertThat(scheduler.getThreadNamePrefix()).isEqualTo( "gcp-pubsub-subscriber-" + fullSubscriptionNameSub2); assertThat(scheduler.isDaemon()).isTrue(); + assertThat( + (ThreadPoolTaskScheduler) + context.getBean("globalPubSubSubscriberThreadPoolScheduler")) + .isNotNull(); assertThat((ExecutorProvider) context.getBean( "subscriberExecutorProvider-" + fullSubscriptionNameSub2)) .isNotNull(); + assertThat((ExecutorProvider) context.getBean("globalSubscriberExecutorProvider")) + .isNotNull(); } finally { pubSubAdmin.deleteSubscription(subscriptionName); pubSubAdmin.deleteTopic(topicName); From 28860a1f0cb5957217dc54af2af755e5201ff5d9 Mon Sep 17 00:00:00 2001 From: Diego Alonso Marquez Palacios Date: Mon, 3 Feb 2025 09:56:32 -0500 Subject: [PATCH 09/11] revert reset on unwanted code sections --- .../cloud/spring/pubsub/core/PubSubConfiguration.java | 3 +++ .../spring/pubsub/support/DefaultSubscriberFactory.java | 7 +++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/spring-cloud-gcp-pubsub/src/main/java/com/google/cloud/spring/pubsub/core/PubSubConfiguration.java b/spring-cloud-gcp-pubsub/src/main/java/com/google/cloud/spring/pubsub/core/PubSubConfiguration.java index 6e253e0090..1167e1a8fa 100644 --- a/spring-cloud-gcp-pubsub/src/main/java/com/google/cloud/spring/pubsub/core/PubSubConfiguration.java +++ b/spring-cloud-gcp-pubsub/src/main/java/com/google/cloud/spring/pubsub/core/PubSubConfiguration.java @@ -34,6 +34,9 @@ public class PubSubConfiguration { private static final Logger logger = LoggerFactory.getLogger(PubSubConfiguration.class); + /** Default number of executor threads. */ + public static final int DEFAULT_EXECUTOR_THREADS = 4; + /** * Automatically extracted user-provided properties. Contains only short subscription keys * user-provided properties, therefore do not use except in initialize(). diff --git a/spring-cloud-gcp-pubsub/src/main/java/com/google/cloud/spring/pubsub/support/DefaultSubscriberFactory.java b/spring-cloud-gcp-pubsub/src/main/java/com/google/cloud/spring/pubsub/support/DefaultSubscriberFactory.java index 1ba9347b97..7b57b35ec8 100644 --- a/spring-cloud-gcp-pubsub/src/main/java/com/google/cloud/spring/pubsub/support/DefaultSubscriberFactory.java +++ b/spring-cloud-gcp-pubsub/src/main/java/com/google/cloud/spring/pubsub/support/DefaultSubscriberFactory.java @@ -499,8 +499,11 @@ Duration getMaxAckExtensionPeriod(String subscriptionName) { if (this.maxAckExtensionPeriod != null) { return this.maxAckExtensionPeriod; } - return Duration.ofSeconds( - this.pubSubConfiguration.computeMaxAckExtensionPeriod(subscriptionName, projectId)); + Long maxAckExtensionPeriod = this.pubSubConfiguration.computeMaxAckExtensionPeriod(subscriptionName, projectId); + if (maxAckExtensionPeriod != null) { + return Duration.ofSeconds(maxAckExtensionPeriod); + } + return null; } @Nullable From c129bda650ce2f68e3ba49100509f363eba6504c Mon Sep 17 00:00:00 2001 From: Diego Alonso Marquez Palacios Date: Mon, 3 Feb 2025 10:16:20 -0500 Subject: [PATCH 10/11] fix units --- .../autoconfigure/pubsub/GcpPubSubAutoConfigurationTests.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-cloud-gcp-autoconfigure/src/test/java/com/google/cloud/spring/autoconfigure/pubsub/GcpPubSubAutoConfigurationTests.java b/spring-cloud-gcp-autoconfigure/src/test/java/com/google/cloud/spring/autoconfigure/pubsub/GcpPubSubAutoConfigurationTests.java index 3c82a21772..0198f4a6a2 100644 --- a/spring-cloud-gcp-autoconfigure/src/test/java/com/google/cloud/spring/autoconfigure/pubsub/GcpPubSubAutoConfigurationTests.java +++ b/spring-cloud-gcp-autoconfigure/src/test/java/com/google/cloud/spring/autoconfigure/pubsub/GcpPubSubAutoConfigurationTests.java @@ -507,7 +507,7 @@ void pullConfig_defaultConfigurationSet() { assertThat( gcpPubSubProperties.computeMaxAckExtensionPeriod( "subscription-name", projectIdProvider.getProjectId())) - .isZero(); + .isNull(); assertThat( gcpPubSubProperties.computeMinDurationPerAckExtension( "subscription-name", projectIdProvider.getProjectId())) From dac6cae9d4d291d52239280d469e75deb20e3a90 Mon Sep 17 00:00:00 2001 From: Diego Alonso Marquez Palacios Date: Mon, 3 Feb 2025 10:23:46 -0500 Subject: [PATCH 11/11] update docs --- docs/src/main/asciidoc/_configprops.adoc | 2 +- docs/src/main/asciidoc/pubsub.adoc | 4 ++-- docs/src/main/asciidoc/spring-integration-pubsub.adoc | 5 +++-- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/docs/src/main/asciidoc/_configprops.adoc b/docs/src/main/asciidoc/_configprops.adoc index d880ce2cdb..6fc7fdc9b9 100644 --- a/docs/src/main/asciidoc/_configprops.adoc +++ b/docs/src/main/asciidoc/_configprops.adoc @@ -73,7 +73,7 @@ |spring.cloud.gcp.pubsub.subscriber.flow-control.limit-exceeded-behavior | | The behavior when the specified limits are exceeded. |spring.cloud.gcp.pubsub.subscriber.flow-control.max-outstanding-element-count | | Maximum number of outstanding elements to keep in memory before enforcing flow control. |spring.cloud.gcp.pubsub.subscriber.flow-control.max-outstanding-request-bytes | | Maximum number of outstanding bytes to keep in memory before enforcing flow control. -|spring.cloud.gcp.pubsub.subscriber.max-ack-extension-period | 0 | The optional max ack extension period in seconds for the subscriber factory. +|spring.cloud.gcp.pubsub.subscriber.max-ack-extension-period | Library default (60 minutes) | The optional max ack extension period in seconds for the subscriber factory. |spring.cloud.gcp.pubsub.subscriber.max-acknowledgement-threads | 4 | Number of threads used for batch acknowledgement. |spring.cloud.gcp.pubsub.subscriber.parallel-pull-count | | The optional parallel pull count setting for the subscriber factory. |spring.cloud.gcp.pubsub.subscriber.pull-endpoint | | The optional pull endpoint setting for the subscriber factory. diff --git a/docs/src/main/asciidoc/pubsub.adoc b/docs/src/main/asciidoc/pubsub.adoc index 8fd35d8fc8..fbdbdbebab 100644 --- a/docs/src/main/asciidoc/pubsub.adoc +++ b/docs/src/main/asciidoc/pubsub.adoc @@ -66,7 +66,7 @@ However, if a per-subscription configuration is not set then the global or defau |=== | Name | Description | Required | Default value | `spring.cloud.gcp.pubsub.subscriber.parallel-pull-count` | The number of pull workers | No | 1 -| `spring.cloud.gcp.pubsub.subscriber.max-ack-extension-period` | The maximum period a message ack deadline will be extended, in seconds | No | 0 +| `spring.cloud.gcp.pubsub.subscriber.max-ack-extension-period` | The maximum period a message ack deadline will be extended, in seconds | No | Library default (60 minutes) | `spring.cloud.gcp.pubsub.subscriber.min-duration-per-ack-extension` | The lower bound for a single mod ack extension period, in seconds | No | 0 | `spring.cloud.gcp.pubsub.subscriber.max-duration-per-ack-extension` | The upper bound for a single mod ack extension period, in seconds | No | 0 | `spring.cloud.gcp.pubsub.subscriber.pull-endpoint` | The endpoint for pulling messages | No | pubsub.googleapis.com:443 @@ -111,7 +111,7 @@ When true, replicates the default behavior before Spring 6.1.x. | No | false | Name | Description | Required | Default value | `spring.cloud.gcp.pubsub.subscription.[subscription-name].fully-qualified-name` | The fully-qualified subscription name in the `projects/[PROJECT]/subscriptions/[SUBSCRIPTION]` format. When this property is present, the `[subscription-name]` key does not have to match any actual resources; it's used only for logical grouping. | No | 1 | `spring.cloud.gcp.pubsub.subscription.[subscription-name].parallel-pull-count` | The number of pull workers. | No | 1 -| `spring.cloud.gcp.pubsub.subscription.[subscription-name].max-ack-extension-period` | The maximum period a message ack deadline will be extended, in seconds. | No | 0 +| `spring.cloud.gcp.pubsub.subscription.[subscription-name].max-ack-extension-period` | The maximum period a message ack deadline will be extended, in seconds. | No | Library default (60 minutes) | `spring.cloud.gcp.pubsub.subscription.[subscription-name].min-duration-per-ack-extension` | The lower bound for a single mod ack extension period, in seconds | No | 0 | `spring.cloud.gcp.pubsub.subscription.[subscription-name].max-duration-per-ack-extension` | The upper bound for a single mod ack extension period, in seconds | No | 0 | `spring.cloud.gcp.pubsub.subscription.[subscription-name].pull-endpoint` | The endpoint for pulling messages. | No | pubsub.googleapis.com:443 diff --git a/docs/src/main/asciidoc/spring-integration-pubsub.adoc b/docs/src/main/asciidoc/spring-integration-pubsub.adoc index 497d0c2430..5d78d6d9f1 100644 --- a/docs/src/main/asciidoc/spring-integration-pubsub.adoc +++ b/docs/src/main/asciidoc/spring-integration-pubsub.adoc @@ -82,8 +82,9 @@ When working with Cloud Pub/Sub, it is important to understand the concept of `a Each subscription has a default `ackDeadline` applied to all messages sent to it. Additionally, the Cloud Pub/Sub client library can extend each streamed message's `ackDeadline` until the message processing completes, fails or until the maximum extension period elapses. -NOTE: In the Pub/Sub client library, default maximum extension period is an hour. However, Spring Framework on Google Cloud disables this auto-extension behavior. -Use the `spring.cloud.gcp.pubsub.subscriber.max-ack-extension-period` property to re-enable it. +NOTE: In the Pub/Sub client library, default maximum extension period is an hour. +The Spring integration delegates the default value resolution to the underlying client library. +If you wish to use a different value, use the `spring.cloud.gcp.pubsub.subscriber.max-ack-extension-period` property. Acknowledging (acking) a message removes it from Pub/Sub's known outstanding messages. Nacking a message resets its acknowledgement deadline to 0, forcing immediate redelivery. This could be useful in a load balanced architecture, where one of the subscribers is having issues but others are available to process messages.