Skip to content

Enhancement Request: Customizable groupExecutorService in Resilience4J CircuitBreakerFactoryΒ #180

Closed

Description

@imyzt

Is your feature request related to a problem? Please describe.

When incorporating openfeign and circuitbreaker in a spring-boot project, our code submits tasks to the executorService for execution. The executorService is created using Executors.newCachedThreadPool(). We intend to customize this thread pool to propagate ThreadLocal information from the main thread to the child threads.

While the Resilience4JCircuitBreakerFactory#configureExecutorService method allows reconfiguration of the thread pool, the groupExecutorService is hard-coded in the code and lacks extensibility, making it challenging to fully implement the desired functionality.

Describe the solution you'd like

We propose making the groupExecutorService customizable or providing a mechanism for extension so that developers can seamlessly implement customizations to pass ThreadLocal information to the child threads.

Additional Information:

Code Reference: Resilience4JCircuitBreakerFactory#configureExecutorService
Current Limitation: Inability to customize groupExecutorService for complete functionality implementation.
Expected Outcome:
We request enhancements to the Resilience4J CircuitBreakerFactory to allow developers to easily customize the groupExecutorService or provide an extension mechanism to fulfill the requirement of passing ThreadLocal information to child threads.

Sample code:

@Configurable
@AllArgsConstructor
public class CircuitBreakerConfiguration implements ApplicationRunner {

    private final Resilience4JCircuitBreakerFactory factory;
    
    @Override
    public void run(ApplicationArguments args) throws Exception {

        ContextThreadPoolExecutor contextThreadPoolExecutor = 
                new ContextThreadPoolExecutor(2, 5, 1, TimeUnit.MINUTES, new ArrayBlockingQueue<>(1024));

        // **change ThreadPoolExecutor**
        factory.configureExecutorService(contextThreadPoolExecutor);
    }
    
    public static class ContextThreadPoolExecutor extends ThreadPoolExecutor {

        public ContextThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) {
            super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
        }

        public void execute(Runnable command) {
            super.execute(wrap(command));
        }

        private static Runnable wrap(Runnable runnable) {
            **SubjectContext context = SubjectContext.getContext();**
            return () -> {
                **SubjectContext.setContext(context);**
                try {
                    runnable.run();
                } finally {
                    **SubjectContext.clear();**
                }
            };
        }
    }
}
@Override
public org.springframework.cloud.client.circuitbreaker.CircuitBreaker create(String id) {
    Assert.hasText(id, "A CircuitBreaker must have an id.");
    Resilience4JCircuitBreaker resilience4JCircuitBreaker = create(id, id, this.executorService);
    return tryObservedCircuitBreaker(resilience4JCircuitBreaker);
}

@Override
public org.springframework.cloud.client.circuitbreaker.CircuitBreaker create(String id, String groupName) {
    Assert.hasText(id, "A CircuitBreaker must have an id.");
    Assert.hasText(groupName, "A CircuitBreaker must have a group name.");
    // **Fixed thread pool creation method, unable to expand**
    final ExecutorService groupExecutorService = executorServices.computeIfAbsent(groupName,
            group -> Executors.newCachedThreadPool());
    Resilience4JCircuitBreaker resilience4JCircuitBreaker = create(id, groupName, groupExecutorService);
    return tryObservedCircuitBreaker(resilience4JCircuitBreaker);
}

Activity

  1. ryanjbaxter commented on Dec 7, 2023

    @ryanjbaxter
    Contributor

    Would you be interested in submitting a PR for this?

  2. imyzt commented on Dec 10, 2023

    @imyzt
    ContributorAuthor

    @ryanjbaxter Of course, Please read my code to ensure it can run in any scenario. #181
    Thanks.

  3. linked a pull request that will close this issueCustomizable groupExecutorService #180 #181on Dec 12, 2023
  4. added this to the 3.0.4 milestone on Dec 12, 2023
  5. added a commit that references this issue on Dec 12, 2023
  6. yong-kurly commented on Mar 6, 2024

    @yong-kurly

    @ryanjbaxter
    I think this patch should be applied in 3.1.x as well.

  7. ryanjbaxter commented on Mar 6, 2024

    @ryanjbaxter
    Contributor

    @yong-kurly it was see 5fa638e

  8. yong-kurly commented on Mar 6, 2024

    @yong-kurly

    Ah! Sorry.
    3.1.1 version has not been released, so I though it was not.

    I'm looking forward 3.1.1 release!

  9. yong-kurly commented on Mar 27, 2024

    @yong-kurly

    Just curious: May I know when the new version(3.1.x) will be released? I am waiting for this feature. πŸ™

  10. ryanjbaxter commented on Mar 27, 2024

    @ryanjbaxter
    Contributor

    This week.

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

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions