Skip to content
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

4.1.3 GCP Adapter - GcfJarLauncher: Failed to lookup function #1164

Open
gfourny-sfeir opened this issue Jul 18, 2024 · 9 comments
Open

4.1.3 GCP Adapter - GcfJarLauncher: Failed to lookup function #1164

gfourny-sfeir opened this issue Jul 18, 2024 · 9 comments

Comments

@gfourny-sfeir
Copy link

Describe the bug
We have still bug on spring-cloud-function-adapter-gcp 4.1.3.
We using Spring Boot 3.3.1 with Spring Cloud Function. When the function is invoking, we have this error:

Failed to execute org.springframework.cloud.function.adapter.gcp.GcfJarLauncher
java.lang.IllegalArgumentException: Failed to lookup function to route based on the value of 'spring.cloud.function.definition' property 'generateAvatar'

It was working with Spring Boot 3.1.x

Sample
pom.xml:

    <properties>
        <java.version>17</java.version>
        <spring-boot.version>3.3.1</spring-boot.version>
        <spring-cloud.version>2023.0.3</spring-cloud.version>
        <function-maven-plugin.version>0.11.0</function-maven-plugin.version>
        <spring-boot-maven-plugin.version>3.3.1</spring-boot-maven-plugin.version>
        <spring-cloud-function-adapter-gcp.version>4.1.3</spring-cloud-function-adapter-gcp.version>
    </properties>


        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-function-context</artifactId>
        </dependency>
        <dependency>
	    <groupId>org.springframework.boot</groupId>
	    <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <!-- Adapteur GCP -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-function-adapter-gcp</artifactId>
        </dependency>
        <!-- Cloud Function Web HTTP-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-function-web</artifactId>
        </dependency>

	<plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>${spring-boot.version}</version>
                <configuration>
                    <outputDirectory>target/deploy</outputDirectory>
                </configuration>
                <dependencies>
                    <dependency>
                        <groupId>org.springframework.cloud</groupId>
                        <artifactId>spring-cloud-function-adapter-gcp</artifactId>
                        <version>${spring-cloud-function-adapter-gcp.version}</version>
                    </dependency>
                </dependencies>
                <executions>
                    <execution>
                        <phase>package</phase>
                        <goals>
                            <goal>build-info</goal>
                            <goal>repackage</goal>
                        </goals>
                        <configuration>
                            <outputDirectory>${basedir}/package</outputDirectory>
                        </configuration>
                    </execution>
                </executions>
        </plugin>

The java Bean :

    @Bean
    Supplier<AvatarResponse> generateAvatar() {
        return avatarGenerator::generate;
    }

The properties:

spring:
  application:
    name: vod-profil-avatar
  cloud:
    function:
      definition: generateAvatar

I have two integration tests to validate the function, all passed:

    @Autowired
    private TestRestTemplate rest;
    @Autowired
    private Storage storage;
    @Value("${u-cf.bucket-name}")
    private String bucketName;
    @Autowired
    private FunctionCatalog functionCatalog;

    @DisplayName("Doit générer un avatar")
    @Test
    void should_generate_avatar() {
        //Given 🔨

        //When 👉
        ResponseEntity<AvatarResponse> avatarResponse = this.rest.getForEntity(URI.create("/"), AvatarResponse.class);

        //then ✅
        assertThat(avatarResponse).isNotNull()
                .satisfies(response -> response.getStatusCode().is2xxSuccessful())
                .extracting(ResponseEntity::getBody)
                .isNotNull()
                .satisfies(input -> {
                    var blob = storage.get(bucketName, input.blobId());
                    assertThat(blob).isNotNull();
                });
    }

    @DisplayName("Doit générer un avatar")
    @Test
    void should_generate_avatar_catalog() {
        //Given 🔨
        Supplier<AvatarResponse> generateAvatar = functionCatalog.lookup(Supplier.class, "generateAvatar");

        //When 👉
        AvatarResponse avatar = generateAvatar.get();

        //Then ✅
        assertThat(avatar)
                .isNotNull()
                .satisfies(input -> {
                    var blob = storage.get(bucketName, input.blobId());
                    assertThat(blob).isNotNull();
                });

    }
@gfourny-sfeir gfourny-sfeir changed the title 4.1.3 GCP Adapteur - GcfJarLauncher: Failed to lookup function 4.1.3 GCP Adapter - GcfJarLauncher: Failed to lookup function Jul 18, 2024
@gfourny-sfeir
Copy link
Author

On invocation, the beans of our application aren't scanned. However, locally with the function plugin, we saw all beans.
To show this, the config of logback-spring.xml:

<logger name="org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLogger" level="DEBUG" additivity="false">
    <appender-ref ref="consoleAppender"/>
</logger>
<logger name="org.springframework.context.annotation.ClassPathBeanDefinitionScanner" level="DEBUG" additivity="false">
    <appender-ref ref="consoleAppender"/>
</logger>
<logger name="org.springframework.beans.factory.support.DefaultListableBeanFactory" level="DEBUG" additivity="false">
    <appender-ref ref="consoleAppender"/>
</logger>

@ihoroshko-n-ix
Copy link

I have the same problem, it looks like beans are not being created unless they are defined in main class (@SpringBootApplication).

I ended up defining all beans like this:

@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(JiraToolsApplication.class, args);
    }

    @Bean
    public WorklogService worklogService() {
        return new WorklogService();
    }

    @Bean
    public WorklogReportFunction worklogFunction() {
        return new WorklogReportFunction(worklogService());
    }
}

It works if you define a bean as functional interface or as a separate class, as I have it:

public class WorklogReportFunction implements Function<Message<BufferedReader>, Message<byte[]>> {
...

@gfourny-sfeir
Copy link
Author

@ihoroshko-n-ix I confirm, this solution works fine.

So the original problem becomes from the scanning step treat by the Spring IoC to find the stereotyps.

We loose on simplicity to create beans but we gain on cold start 😅

Once again, thanks for your solution

@laurentiu-miu
Copy link

@ihoroshko-n-ix & @gfourny-sfeir
Could you please provide a link to a GitHub repo with the code using spring boot 3.3.x and spring-cloud-function-adapter-gcp 4.1.3?
I'd like to test it and understand how it behaves, especially if the beans are not being scanned.
How could it still function in this case?

@balaji1974
Copy link

After hours of working on this issue, I found that the issue is with Spring boot newer version which does not have support yet and hence downgrade your Spring boot version to 3.1.x in my case tested with 3.1.10 version and it works fine. Look at my example in https://github.com/balaji1974/functions

And I solved this issue by following this thread on the same issue:
#1085

@rajakumare1
Copy link

@ihoroshko-n-ix @gfourny-sfeir Can you post the code in Github repo as I am not sure of how to inject the service into the Function interface

@gfourny-sfeir
Copy link
Author

@rajakumare1 I couldn't share our repos because they're private.
You need to declare your Bean in the main class like this:

@SpringBootApplication
public class VodProfilAvatarApplication {

    public static void main(String[] args) {
        SpringApplication.run(VodProfilAvatarApplication.class, args);
    }

    @Bean
    RestClient restClient(RestClient.Builder builder, VodProfilAvatarProperties properties) {
        return builder.baseUrl(properties.avatarGeneratorBaseUrl()).build();
    }

    //Business service without @Service or @Component annotation
    @Bean
    AvatarWriter avatarWriter(Storage storage, VodProfilAvatarProperties properties) {
        return new AvatarWriter(storage, properties);
    }

    //Business service without @Service or @Component annotation
    @Bean
    AvatarClient avatarClient(RestClient restClient) {
        return new AvatarClient(restClient);
    }

    //Business service without @Service or @Component annotation
    @Bean
    AvatarGenerator avatarGenerator(AvatarClient avatarClient, AvatarWriter avatarWriter) {
        return new AvatarGenerator(avatarClient, avatarWriter);
    }

    /**
     * {@link Supplier} called by Cloud Function and refers in application.yaml
     *
     * @return {@link Supplier<String>}
     */
    @Bean
    Supplier<AvatarResponse> generateAvatar(AvatarGenerator avatarGenerator) {
        return avatarGenerator::generate;
    }
}

In your application.yaml:

spring:
  application:
    name: vod-profil-avatar
  cloud:
    function:
      definition: generateAvatar #Name of the bean

@gfourny-sfeir
Copy link
Author

@olegz We suspect the bug comes from the FunctionInvoker class in the adapter code by these lines:

Thread.currentThread() // TODO: remove after upgrading to 1.0.0-alpha-2-rc5
			.setContextClassLoader(FunctionInvoker.class.getClassLoader());

❓ Why

Because the classLoader used to scan is provides these lines and cannot scan the package created by our applications

@SND33
Copy link

SND33 commented Nov 27, 2024

Happy to report that both the issue mentioned in #1085 and this one are resolved for me after upgrading to version 4.1.4 (tested with Spring Cloud Release Train 2023.0.4 and Spring Boot 3.3.6). My Spring Boot cloud function app starts correctly again when deployed to GCP, and all beans are correctly scanned 👍.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants