Skip to content

AsyncCustomAutoConfiguration does not post process a bean of type AsyncConfigurer #1022

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

Closed
dhwajad opened this issue Jul 2, 2018 · 9 comments

Comments

@dhwajad
Copy link

dhwajad commented Jul 2, 2018

Here is a sample application (spring-cloud-sleuth:2.0.0.RELEASE) that has a custom AsyncConfigurer with a ThreadPoolTaskExecutor and core pool size of 10. When the spring boot application starts the following info log shows up-

INFO  [main] o.s.c.s.PostProcessorRegistrationDelegate$BeanPostProcessorChecker - Bean 'asyncConfigurer' of type [sleuth.webmvc.frontend.FrontendAsyncConfigurerSupport$1] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
 1203 --- [           main] trationDelegate$BeanPostProcessorChecker : Bean 'asyncConfigurer' of type [sleuth.webmvc.frontend.FrontendAsyncConfigurerSupport$1] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)

The application spawns 3 threads per request (http://localhost:8080/), and the expectation is the traceId is same for the spawned threads as that of the main thread. This is fine for the first 3 requests, but the 4th request to the RestController is when the threads from the thread pool are reused and these reused threads aren't propagated the new traceId but hold onto the traceId from the previous requests.

The only way to solve this issue at present is to update application code; and wrap a ThreadPoolTaskExecutor in a LazyTraceExecutor. Easy enough but not ideal when trying to instrument sleuth by just adding it to the dependencies.

@marcingrzejszczak
Copy link
Contributor

Interesting I must have missed that particular proxy creation. Thanks for the pointers.

@marcingrzejszczak
Copy link
Contributor

Related issue in core - https://jira.spring.io/browse/SPR-17021

@marcingrzejszczak
Copy link
Contributor

The issue in core https://jira.spring.io/browse/SPR-17021 has been fixed so I guess once Boot upgrades to 5.1 we'll be able to fix this one

@michael-wirth
Copy link

Just tested it with Spring 5.1.3 and Spring Boot 2.1.1, it still doesn't seem to work, Is there anything open?

@marcingrzejszczak
Copy link
Contributor

I don't see that when using latest 2.1.0.BUILD-SNAPSHOT version of Spring Cloud Sleuth. @michael-wirth can you show me how you've managed to replicate this?

@marcingrzejszczak
Copy link
Contributor

Ah, I've opened a wrong branch. Now I see it

@marcingrzejszczak
Copy link
Contributor

Let's start with a workaround... It's enough to change your bean to be declared via a static method and be annotated with @Role(BeanDefinition.ROLE_INFRASTRUCTURE).

package sleuth.webmvc.frontend;

import java.util.concurrent.Executor;

import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Role;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.annotation.AsyncConfigurerSupport;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

@Configuration
@EnableAsync
public class FrontendAsyncConfigurerSupport {

    @Autowired
    BeanFactory beanFactory;

    @Bean
    @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
    public static AsyncConfigurer asyncConfigurer() {
        return new AsyncConfigurerSupport() {
            @Override
            public Executor getAsyncExecutor() {
                ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
                executor.setCorePoolSize(10);
                executor.setMaxPoolSize(10);
                executor.setQueueCapacity(500);
                executor.setThreadNamePrefix("AsyncExecutor-");
                executor.initialize();

                return executor;
                //return new LazyTraceExecutor(beanFactory, executor);
            }
        };
    }

}

Now I'll continue the analysis to check the root cause.

@marcingrzejszczak
Copy link
Contributor

marcingrzejszczak commented Dec 19, 2018

Actually your setup is wrong. Your @Configuration class should implement the interface. Then it's enough for you to add the @Role(BeanDefinition.ROLE_INFRASTRUCTURE) on it.

package sleuth.webmvc.frontend;

import java.util.concurrent.Executor;

import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Role;
import org.springframework.scheduling.annotation.AsyncConfigurerSupport;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

@Configuration
@EnableAsync
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public class FrontendAsyncConfigurerSupport extends AsyncConfigurerSupport {

    @Override
    public Executor getAsyncExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(10);
        executor.setMaxPoolSize(10);
        executor.setQueueCapacity(500);
        executor.setThreadNamePrefix("AsyncExecutor-");
        executor.initialize();

        return executor;
        //return new LazyTraceExecutor(beanFactory, executor);
    }

}

@marcingrzejszczak
Copy link
Contributor

Added an entry in the docs about it

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

No branches or pull requests

3 participants