Fix not overriding cloud stream properties (#2582)

Co-authored-by: vasilchev <vasil.ilchev@bosch.com>
This commit is contained in:
Vasil Ilchev
2025-08-01 18:15:56 +03:00
committed by GitHub
parent fd9c0fc50d
commit c79e35b9de
5 changed files with 44 additions and 89 deletions

View File

@@ -50,8 +50,18 @@ hawkbit.lock=inMemory
# Disable discovery client of spring-cloud-commons
spring.cloud.discovery.enabled=false
# remote events configuration
# remote events configuration
spring.cloud.function.definition=fanoutEventConsumer;serviceEventConsumer
spring.cloud.stream.default.content-type=application/remote-event-json
# Optional: Use protostuff (if enabled)
# spring.cloud.stream.default.content-type=application/binary+protostuff
# -- Consumer bindings --
spring.cloud.stream.bindings.fanoutEventConsumer-in-0.destination=fanoutEventChannel
spring.cloud.stream.bindings.serviceEventConsumer-in-0.destination=serviceEventChannel
# -- Producer bindings (for StreamBridge) --
spring.cloud.stream.bindings.fanoutEventChannel.destination=fanoutEventChannel
spring.cloud.stream.bindings.serviceEventChannel.destination=serviceEventChannel
spring.cloud.stream.bindings.serviceEventConsumer-in-0.group=${spring.application.name}
# Swagger Configuration / https://springdoc.org/v2/#properties
springdoc.api-docs.version=openapi_3_0

View File

@@ -36,5 +36,14 @@ hawkbit.lock=inMemory
spring.cloud.discovery.enabled=false
# remote events configuration
spring.cloud.function.definition=fanoutEventConsumer;serviceEventConsumer
spring.cloud.stream.default.content-type=application/remote-event-json
# Optional: Use protostuff (if enabled)
# spring.cloud.stream.default.content-type=application/binary+protostuff
# -- Consumer bindings --
spring.cloud.stream.bindings.fanoutEventConsumer-in-0.destination=fanoutEventChannel
spring.cloud.stream.bindings.serviceEventConsumer-in-0.destination=serviceEventChannel
# -- Producer bindings (for StreamBridge) --
spring.cloud.stream.bindings.fanoutEventChannel.destination=fanoutEventChannel
spring.cloud.stream.bindings.serviceEventChannel.destination=serviceEventChannel
spring.cloud.stream.bindings.serviceEventConsumer-in-0.group=${spring.application.name}

View File

@@ -54,5 +54,14 @@ springdoc.swagger-ui.csrf.enabled=true
springdoc.swagger-ui.doc-expansion=none
# remote events configuration
spring.cloud.function.definition=fanoutEventConsumer;serviceEventConsumer
spring.cloud.stream.default.content-type=application/remote-event-json
# Optional: Use protostuff (if enabled)
# spring.cloud.stream.default.content-type=application/binary+protostuff
# spring.cloud.stream.default.content-type=application/binary+protostuff
# -- Consumer bindings --
spring.cloud.stream.bindings.fanoutEventConsumer-in-0.destination=fanoutEventChannel
spring.cloud.stream.bindings.serviceEventConsumer-in-0.destination=serviceEventChannel
# -- Producer bindings (for StreamBridge) --
spring.cloud.stream.bindings.fanoutEventChannel.destination=fanoutEventChannel
spring.cloud.stream.bindings.serviceEventChannel.destination=serviceEventChannel
spring.cloud.stream.bindings.serviceEventConsumer-in-0.group=${spring.application.name}

View File

@@ -9,12 +9,10 @@
*/
package org.eclipse.hawkbit.event;
import java.io.IOException;
import java.util.concurrent.Executor;
import java.util.function.Consumer;
import jakarta.annotation.PostConstruct;
import io.protostuff.ProtostuffIOUtil;
import io.protostuff.Schema;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.hawkbit.repository.event.ApplicationEventFilter;
import org.eclipse.hawkbit.repository.event.EventPublisherHolder;
@@ -22,9 +20,8 @@ import org.eclipse.hawkbit.repository.event.remote.AbstractRemoteEvent;
import org.eclipse.hawkbit.repository.event.remote.RemoteTenantAwareEvent;
import org.eclipse.hawkbit.security.SystemSecurityContext;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.cloud.stream.config.BindingProperties;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.annotation.Bean;
@@ -33,8 +30,6 @@ import org.springframework.context.event.ApplicationEventMulticaster;
import org.springframework.context.event.SimpleApplicationEventMulticaster;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.core.ResolvableType;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.io.support.ResourcePropertySource;
import org.springframework.messaging.converter.MessageConverter;
/**
@@ -44,23 +39,6 @@ import org.springframework.messaging.converter.MessageConverter;
@Configuration
public class EventPublisherConfiguration {
private final ConfigurableEnvironment environment;
public EventPublisherConfiguration(ConfigurableEnvironment environment) {
this.environment = environment;
}
@PostConstruct
public void registerProperties() {
try {
ResourcePropertySource props = new ResourcePropertySource("classpath:/hawkbit-events-defaults.properties");
// load manually to ensure that they are with the lowest precedence allowing to override them
environment.getPropertySources().addLast(props);
} catch (IOException ex) {
log.error("Failed to load default properties for event publisher", ex);
}
}
/**
* Server internal event publisher that allows parallel event processing if the event listener is marked as so.
*
@@ -128,33 +106,29 @@ public class EventPublisherConfiguration {
}
@Bean
@ConditionalOnProperty(name = "org.eclipse.hawkbit.events.remote-enabled", havingValue = "true")
public Consumer<AbstractRemoteEvent> serviceEventConsumer(ApplicationEventPublisher publisher) {
return publisher::publishEvent;
}
@Bean
@ConditionalOnProperty(name = "org.eclipse.hawkbit.events.remote-enabled", havingValue = "true")
public Consumer<AbstractRemoteEvent> fanoutEventConsumer(ApplicationEventPublisher publisher) {
return publisher::publishEvent;
}
@Bean
@ConditionalOnProperty(name = "org.eclipse.hawkbit.events.remote-enabled", havingValue = "true")
public MessageConverter eventMessageConverter(BindingProperties bindingProperties) {
@ConditionalOnClass({ Schema.class, ProtostuffIOUtil.class })
protected static class EventProtostuffConfiguration {
final String contentType = bindingProperties.getContentType();
if (contentType == null) {
throw new IllegalStateException("RemoteEvents are enabled and Content type must be specified in spring.cloud.stream.default.content-type.");
}
if (contentType.equals("application/binary+protostuff")) {
/**
* @return the protostuff io message converter
*/
@Bean
public MessageConverter eventProtostuffMessageConverter() {
return new EventProtoStuffMessageConverter();
} else if (contentType.equals("application/remote-event-json")) {
return new EventJacksonMessageConverter();
} else {
throw new IllegalStateException("Unsupported content type: " + contentType + ". Supported types: application/x-protostuff, application/remote-event-json");
}
}
@Bean
public MessageConverter eventJacksonMessageConverter() {
return new EventJacksonMessageConverter();
}
}

View File

@@ -1,47 +0,0 @@
#
# Copyright (c) 2015 Bosch Software Innovations GmbH and others
#
# This program and the accompanying materials are made
# available under the terms of the Eclipse Public License 2.0
# which is available at https://www.eclipse.org/legal/epl-2.0/
#
# SPDX-License-Identifier: EPL-2.0
#
org.eclipse.hawkbit.events.remote-enabled=true
spring.cloud.function.definition=fanoutEventConsumer;serviceEventConsumer
spring.cloud.stream.default.content-type=application/remote-event-json
# -- Consumer bindings --
spring.cloud.stream.bindings.fanoutEventConsumer-in-0.destination=fanoutEventChannel
spring.cloud.stream.bindings.serviceEventConsumer-in-0.destination=serviceEventChannel
# -- Producer bindings (for StreamBridge) --
spring.cloud.stream.bindings.fanoutEventChannel.destination=fanoutEventChannel
spring.cloud.stream.bindings.serviceEventChannel.destination=serviceEventChannel
spring.cloud.stream.bindings.serviceEventConsumer-in-0.group=${spring.application.name}
# Performance
spring.cloud.stream.rabbit.binder.compressionLevel=0
spring.cloud.stream.rabbit.bindings.fanoutEventConsumer-in-0.consumer.anonymousGroupPrefix=${spring.application.name}-
spring.cloud.stream.rabbit.bindings.fanoutEventConsumer-in-0.consumer.durableSubscription=false
spring.cloud.stream.rabbit.bindings.fanoutEventConsumer-in-0.consumer.maxConcurrency=1
spring.cloud.stream.rabbit.bindings.fanoutEventConsumer-in-0.consumer.requeueRejected=false
spring.cloud.stream.rabbit.bindings.fanoutEventConsumer-in-0.consumer.prefetch=100
spring.cloud.stream.rabbit.bindings.serviceEventConsumer-in-0.consumer.maxConcurrency=1
spring.cloud.stream.rabbit.bindings.serviceEventConsumer-in-0.consumer.requeueRejected=false
spring.cloud.stream.rabbit.bindings.serviceEventConsumer-in-0.consumer.prefetch=100
spring.cloud.stream.rabbit.bindings.fanoutEventChannel.producer.declareExchange=false
spring.cloud.stream.rabbit.bindings.fanoutEventChannel.producer.batchingEnabled=true
spring.cloud.stream.rabbit.bindings.fanoutEventChannel.producer.batchSize=1000
spring.cloud.stream.rabbit.bindings.fanoutEventChannel.producer.batch-buffer-limit=100000
spring.cloud.stream.rabbit.bindings.fanoutEventChannel.producer.deliveryMode=NON_PERSISTENT
spring.cloud.stream.rabbit.bindings.serviceEventChannel.producer.declareExchange=false
spring.cloud.stream.rabbit.bindings.serviceEventChannel.producer.batchingEnabled=true
spring.cloud.stream.rabbit.bindings.serviceEventChannel.producer.batchSize=1000
spring.cloud.stream.rabbit.bindings.serviceEventChannel.producer.batch-buffer-limit=100000
spring.cloud.stream.rabbit.bindings.serviceEventChannel.producer.deliveryMode=NON_PERSISTENT