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

Thread-pool-bulkhead and Bulkhead #826

Closed
krishnaputhran opened this issue Jan 29, 2020 · 5 comments
Closed

Thread-pool-bulkhead and Bulkhead #826

krishnaputhran opened this issue Jan 29, 2020 · 5 comments
Labels

Comments

@krishnaputhran
Copy link

Thanks for raising a Resilience4j issue.
Please provide a brief description of your problem along with the versions you are using.
If possible, please also consider putting together a complete JUnit test that reproduces the issue.

Resilience4j version:
1.2.0
Java version:
1.8
Problem description:
I am unable to find an example with clarity or documentation with clarity as what is ThreadPoolBuilkhead, BulkHead and Semaphore Bulkhead are the same?. I am using annotation based BulkHead pattern. I have the following configuration.

resilience4j.bulkhead:
configs:
default:
registerHealthIndicator: true
maxConcurrentCalls: 5

resilience4j.thread-pool-bulkhead:
configs:
default:
registerHealthIndicator: true
maxThreadPoolSize: 1
coreThreadPoolSize: 1
queueCapacity: 1

I have lost bit clarity on what are the key differences between the two builkhead implementations when it comes to usecases. The documentation doesn't give info regarding the same. So I need help interns of documentation or a simple clarification would help me a lot in using this library with more understanding.

Thanks
Krishna

@RobWin
Copy link
Member

RobWin commented Jan 29, 2020

Bulkhead -> Semaphore-based Bulkhead
ThreadPoolBulkhead -> Threadpool-based Bulkhead

The Semaphore-based Bulkhead runs your code in the current Thread and controls the number of concurrent threads by a Semaphore.
The Threadpool-based Bulkhead runs your code in a Thread from a Thread Pool and controls the number of concurrent threads by a bounded queue and thread pool.

@krishnaputhran
Copy link
Author

Thank you RobWin for the explanation, it was very helpful. I tried ThreadPool with @bulkhead annotation and I get the following error. is ThreadPoolBulkHead is supported in the current release?

My Code:

  @Bulkhead(name = "", fallbackMethod = "bulkHeadFallback", type = Bulkhead.Type.THREADPOOL) // if the name is empty, it takes default config values 
public ResponseEntity<BarcodeResponse> getBarcodeResponse(AnalyseIdentifier  analyseIdentifier,

{
// call to some remote servcie
}

Error:

ThreadPool bulkhead is only applicable for completable futures

    at org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor.invoke(MethodBeforeAdviceInterceptor.java:56)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:175)
    at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:88)
    at jp.co.toshibatec.ngp.conductor.aspect.LoggingAccess.time(LoggingAccess.java:160)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:567)
    at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:644)
    at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:633)
    at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:70)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:175)
    at org.springframework.aop.framework.adapter.AfterReturningAdviceInterceptor.invoke(AfterReturningAdviceInterceptor.java:55)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:175)
    at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:93)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:688)
    at jp.co.toshibatec.ngp.conductor.plugins.item_bundle.web.ItemController$$EnhancerBySpringCGLIB$$b74a21ee.itemOperation(<generated>)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:567)

Your response would be highly appreciated

@RobWin
Copy link
Member

RobWin commented Jan 30, 2020

Yes that's correct. The ThreadPoolBulkhead runs tasks in a thread pool and returns a CompletionStage (CompletableFuture). The method’s return type must be CompletableFuture<BarcodeResponse> instead of BarcodeResponse, a requirement for any asynchronous service. Your code must do return CompletableFuture.completedFuture(response);
It can't return a ResponseEntity<BarcodeResponse>.

It's comparable to Spring's @Async annotation. Please see: https://spring.io/guides/gs/async-method/

@krishnaputhran
Copy link
Author

Thanks RobWin. You are a champ

@ngDevendra
Copy link

Bulkhead -> Semaphore-based Bulkhead
ThreadPoolBulkhead -> Threadpool-based Bulkhead

The Semaphore-based Bulkhead runs your code in the current Thread and controls the number of concurrent threads by a Semaphore.
The Threadpool-based Bulkhead runs your code in a Thread from a Thread Pool and controls the number of concurrent threads by a bounded queue and thread pool.

Hi RobWin - Can you please explain this point with the help of example?

I've two downstream services which I want to call in a resilient manner i.e. Allow certain threads allocated to call to Service A and certain to call Service B. I understood the 'maxWaitDuration' and 'maxConcurrentCalls' very well. But not able to differentiate 'maxThreadPoolSize, coreThreadPoolSize, queueCapacity' from 'maxWaitDuration' and 'maxConcurrentCalls' ? Also can we use them together or we have to use either bulkhead or threadpoolbulkhead ? I gone through demo application but can't find the practical difference (or may be I'm not able to get it)

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

No branches or pull requests

3 participants