-
Notifications
You must be signed in to change notification settings - Fork 618
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Wrong functionType is determined for the FunctionInvocationWrapper #409
Comments
Related bug in Spring Cloud Stream, for posterity: spring-cloud/spring-cloud-stream#1794 |
I've been reading the documentation updates in Spring Cloud Stream. The project is moving away from being a light Spring Integration input/output router, and instead towards enabling pure microservices/functions, which got me to wonder if we are no longer using it philosophically correctly. Instead of trying to figure out how to exclude the binder infrastructure bean that happens to look like a functional interface from being discovered, it may be preferable to explicitly mark it as "those are not the functional beans you are looking for". Would Spring Cloud Function or Stream consider adding an annotation like |
Elena There are several issues at play here, so I decided to do a little writeup that I hope to turn into a blog. But first let me give you the short one: The core issue is that in s-c-function we determine function type based on the signatures of the method, class etc., otherwise we’re giving you an option to configure all of it yourself via FunctionRegistration class. In your case the signature of the factory method in question is not a function type (not Supplier, Function or Consumer), however the instance returned by this factory method and the resulting bean is a function (Supplier) and that is the problem which we did not account for in s-c-function. So regardless of everything else, that is the root of the problem and it needs to be addressed. Now the long one. . . Interesting perception - "being a light Spring Integration input/output router. . .”, but I have to disagree, since it never has been about Spring Integration(SI) and/or router. In fact this statement shows part of the problem where SI (framework of choice to support some of the internal requirements of spring-cloud-stream(SCSt), was somehow perceived to be the core of spring-cloud-stream in such way that many perceive SCSt to be an extension to SI. It is not. It has always been about pure microservices. Just read the first sentence of our front page "Spring Cloud Stream is a framework for building highly scalable event-driven microservices connected with shared messaging systems." To function or not to function Let's look at the following two code snippets Annotation-based: @SpringBootApplication
@EnableBinding(Processor.class)
public class SampleApplication {
@StreamListener(Processor.INPUT)
@SendTo(Processor.OUTPUT)
public String uppercase(String value) {
return value.toUpperCase();
}
} Function based: @SpringBootApplication
public class SampleApplication {
@Bean
public Function<String, String> uppercase() {
return value -> value.toUpperCase();
}
} Both are valid and fully functioning SCSt applications. Both are doing the same thing and both will produce the same result except that in the annotation-based example user has to be aware of SCSt abstractions (i.e., messaging, channels, bindings etc.) while the code has nothing to do with any of these abstractions. That raises a question why? Spring has always been about “you worry about functional requirements and we take care of non-functional (boilerplate)”. So, in he context of SCSt as a framework and its core goals of "binding and activation" we quickly realised that these abstractions are boilerplate and should not be leaked into the user’s code especially in the form of annotations as they contribute to binary dependency of such code on SCSt for no valid reason. So with that what I am also saying is that we are starting on our slow journey of moving away from annotation-based programming model and into a more spring-boot aligned opinionated model of clearly documented and intuitive convention with limited out-of-the-box configuration required from the user. So finally to your case where something in your configuration (outside of your control) fits the category of function, but that is/was not your intention. Valid, interesting and we definitely need to provide a path to opt-out and that is what we’re working on, but I hope I was able to convince you that while you are correct in requesting such option, annotation would not be the right approach here, so I am considering a property. Please feel free to provide any feedback Cheers |
That's a good blog post as is! |
So the fix is in and I believe it actually addresses the issue. Basically with this fix during the default discovery process (process where function definition is not provided) we no longer treat instance of Function, Supplier or Consumer as functional if its declared type is not actually Function, Supplier or Consumer (see example below):
So for the case in SCSt where it was firs discovered it will no longer be discovered in the first place. Also, the above solution is valid IMHO for another reason. If we can't properly discover the actual type of the function (it's input/output argument types) we can't perform any type conversion effectively pushing a problem down the stack instead of addressing it. |
Removing workaround now that spring-cloud/spring-cloud-function#409 is resolved. Fixes #1919.
Excellent! I backed out the Thank you for your help! |
…dPlatform#1923) Removing workaround now that spring-cloud/spring-cloud-function#409 is resolved. Fixes GoogleCloudPlatform#1919.
We have a bean like this:
where a target instance is a
Supplier
, accordingSchedulers.CachedScheduler
extension. And this one is registered in theFunctionCatalog
as aSupplier
.But at the same time it looks like
functionType
for theFunctionInvocationWrapper
is determined from the bean definition type.And in this case we have a plain:
so, that
Disposable
is set into thefunctionType
, which leads to an exception like this when we perform function lookup:For me it sounds like we really need to check a bean definition type (not the target object) before registering into the
FunctionCatalog
.Also would be great to improve that exception message to let us know which bean is guilty.
The text was updated successfully, but these errors were encountered: