spring-integration icon indicating copy to clipboard operation
spring-integration copied to clipboard

Additional support for property placeholders in org.springframework.integration.annotation.ServiceActivator

Open kabennett opened this issue 3 years ago • 5 comments

Please add support for property placholders to be used within the inputChannel and outputChannel definitions. Our Kinesis channel names are different per environment (e.g., dev-destination, test-destination, prod-destination), so in order to be able to specify the error channel name in the <destination>.<group>.errors format as specified here, we want to be able to use property placeholders for these (e.g., @ServiceActivator(inputChannel = "${env}-destination.group.errors"). Currently, we'd have to have a @ServiceActivator specified per environment with a hardcoded <destination>.<group>.errors to handle stream-specific errors (vs. using the global errorChannel).

kabennett avatar Aug 04 '22 15:08 kabennett

Well, I would stay away from such a feature since that inputChannel is really about a bean reference. Let's see if existing workarounds are OK with you before going deep into hard discuss "do or do not".

First of all you can replace simply your @ServiceActivator with an IntegrationFlow:

@Bean 
IntegrationFlow myErrorHandlingFlow(@Value(""${env}-destination.group.errors") String errorChannel) {
     return IntegrationFlows.from(errorChannel)
                         .handle(...)
                         .get();
}

Another way is to have profile-specific configuration for channel beans and delegate to your service activator via @BridgeTo:

@Configuration
@Profile("dev")
class DevConfiguration {

     @Bean(name = "dev-destination.group.errors")
     @BridgeTo("myErrorHandlerChannel")
     MessageChannel devErrorChannel() { 
          return new DirectChannel();
     }
}

where your service activator would be just like this:

@ServiceActivator(inputChannel = "myErrorHandlerChannel")

On the other hand: why would one have destinations with env prefix? Why the same name cannot be used in different environments? Something is off with your architecture: independently of the env, your solution should behave the same. In other words the microservice must be free from knowledge about an environment it is deployed in. At least that has to be true for destinations. Yes: the server and its configuration could be different, but that's exactly infrastructure - nothing business-specific. The destination name is already a business aspect and it must not be different from different envs.

It might be even better to raise the concern about error channel naming against Spring Cloud Stream. Probably something like a binding name alias. So, you can have different destinations, but you always can set them to the same error channel bean name expected in your code. Again: I worry more about wrong connection between the code and environment. In my feeling the code has to be same, but env has to adjust to it expectations, not wise-versa. You compile once and run everywhere!

artembilan avatar Aug 04 '22 16:08 artembilan

In principle I agree with your point about the destination names, but I lost that argument (i.e., my client wants the environment prefix). I fought to have the streams named consistently throughout all environments, but in the end it wasn't my call. And that brings me to the point that, even if it's not the best decision architecturally, it's a working solution. So, with the current solution in place, if we had the ability to specify property placeholders as requested, this would be of benefit to us and potentially other users.

kabennett avatar Aug 04 '22 17:08 kabennett

With your IntegrationFlow example, how do I get access to the ErrorMessage at runtime in a similar way that I do with the error handling @ServiceActivator I have in place currently?

kabennett avatar Aug 04 '22 17:08 kabennett

Since you didn't show the body of your error handler, I also did not in my .handle().

Technically you still can have that method and you can call it like this: .handle("myErrorHandlerService", "myErrorHandlerMethod"). Please, see all the possible .handle() variants in the IntegrationFlowDefinition to satisfy your requirements. More docs are here: https://docs.spring.io/spring-integration/docs/current/reference/html/dsl.html#java-dsl-handle

artembilan avatar Aug 04 '22 17:08 artembilan

Thank you @artembilan. I have opened an issue with the Spring Cloud Stream project here.

kabennett avatar Aug 04 '22 17:08 kabennett

Closed as Won't Fix with respective explanation above.

artembilan avatar Sep 08 '22 18:09 artembilan