Close

Spring Cloud - Circuit Breaker Hystrix, concurrent requests and default thread pool size

[Updated: Aug 11, 2019, Created: Aug 11, 2019]

By default, Hystrix Circuit Breaker uses a thread pool to handle concurrent requests.

Hystrix various thread pool related properties determines thread pool characteristics. Hystrix uses Java ThreadPoolExecutor to handle concurrent requests.

By default Hystrix uses coreSize of 10 threads and it does not uses any waiting queue. (details). That means if number of concurrent request at a time is more than 10, the rest of the requests are rejected (failed, redirected to the fallback method) and according to other default settings (as seen in this example) circuit might trip if within 10 seconds 20 requests are received and more than 50% of which are failed.

Example

In this example, we are not modifying any defaults, so if we make more than 10 concurrent requests at a time, remaining calls will fallback.

Using @HystrixCommand

package com.logicbig.example;

import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import org.springframework.stereotype.Service;
import java.util.concurrent.TimeUnit;

@Service
public class MyService {
  @HystrixCommand(fallbackMethod = "defaultDoSomething")
  public void doSomething(int input) {
      System.out.printf("thread: %s, input: %s, output: %s%n",
              Thread.currentThread().getName(), input, 100 / input);
  }

  public void defaultDoSomething(int input, Throwable throwable) {
      System.out.printf("fallback, thread: %s input:%s, exception:%s%n",
              Thread.currentThread().getName(), input, throwable);
  }
}

Making concurrent requests

package com.logicbig.example;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.context.ConfigurableApplicationContext;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

@SpringBootApplication
@EnableCircuitBreaker
public class CircuitBreakerMain {
  public static void main(String[] args) throws InterruptedException {
      ConfigurableApplicationContext ctx = SpringApplication.run(CircuitBreakerMain.class, args);
      MyService myService = ctx.getBean(MyService.class);

      System.out.println("Main Thread: "+Thread.currentThread().getName());
      System.out.println("-- calling doSomething(1) 20 times --");
      int n = 20;
      ExecutorService es = Executors.newFixedThreadPool(n);
      for (int i = 0; i < n; i++) {
          int finalI = i;
          es.submit(() -> myService.doSomething(finalI +1)
          );
      }
      es.shutdown();
      es.awaitTermination(10, TimeUnit.SECONDS);

      TimeUnit.SECONDS.sleep(5);
      System.out.println("-- after 5 sec --");
      myService.doSomething(2);

      TimeUnit.SECONDS.sleep(5);
      System.out.println("-- after 5 sec --");
      myService.doSomething(2);
  }
}

Output

Main Thread: main
-- calling doSomething(1) 20 times --
fallback, thread: pool-1-thread-10 input:10, exception:java.util.concurrent.RejectedExecutionException: Task java.util.concurrent.FutureTask@3193469e rejected from java.util.concurrent.ThreadPoolExecutor@3c48d178[Running, pool size = 7, active threads = 7, queued tasks = 0, completed tasks = 0]
fallback, thread: pool-1-thread-6 input:6, exception:java.util.concurrent.RejectedExecutionException: Task java.util.concurrent.FutureTask@620144a1 rejected from java.util.concurrent.ThreadPoolExecutor@3c48d178[Running, pool size = 8, active threads = 8, queued tasks = 0, completed tasks = 0]
fallback, thread: pool-1-thread-1 input:1, exception:java.util.concurrent.RejectedExecutionException: Task java.util.concurrent.FutureTask@ba86474 rejected from java.util.concurrent.ThreadPoolExecutor@3c48d178[Running, pool size = 4, active threads = 4, queued tasks = 0, completed tasks = 0]
fallback, thread: pool-1-thread-15 input:15, exception:java.util.concurrent.RejectedExecutionException: Task java.util.concurrent.FutureTask@131754de rejected from java.util.concurrent.ThreadPoolExecutor@3c48d178[Running, pool size = 4, active threads = 4, queued tasks = 0, completed tasks = 0]
fallback, thread: pool-1-thread-3 input:3, exception:java.util.concurrent.RejectedExecutionException: Task java.util.concurrent.FutureTask@304d917a rejected from java.util.concurrent.ThreadPoolExecutor@3c48d178[Running, pool size = 7, active threads = 7, queued tasks = 0, completed tasks = 0]
fallback, thread: pool-1-thread-2 input:2, exception:java.util.concurrent.RejectedExecutionException: Task java.util.concurrent.FutureTask@2baee5f0 rejected from java.util.concurrent.ThreadPoolExecutor@3c48d178[Running, pool size = 6, active threads = 6, queued tasks = 0, completed tasks = 0]
fallback, thread: pool-1-thread-4 input:4, exception:java.util.concurrent.RejectedExecutionException: Task java.util.concurrent.FutureTask@14925692 rejected from java.util.concurrent.ThreadPoolExecutor@3c48d178[Running, pool size = 6, active threads = 6, queued tasks = 0, completed tasks = 0]
fallback, thread: pool-1-thread-20 input:20, exception:java.util.concurrent.RejectedExecutionException: Task java.util.concurrent.FutureTask@614c43d6 rejected from java.util.concurrent.ThreadPoolExecutor@3c48d178[Running, pool size = 5, active threads = 5, queued tasks = 0, completed tasks = 0]
fallback, thread: pool-1-thread-16 input:16, exception:java.util.concurrent.RejectedExecutionException: Task java.util.concurrent.FutureTask@62562e3a rejected from java.util.concurrent.ThreadPoolExecutor@3c48d178[Running, pool size = 6, active threads = 6, queued tasks = 0, completed tasks = 0]
fallback, thread: pool-1-thread-19 input:19, exception:java.util.concurrent.RejectedExecutionException: Task java.util.concurrent.FutureTask@65a8b44e rejected from java.util.concurrent.ThreadPoolExecutor@3c48d178[Running, pool size = 5, active threads = 5, queued tasks = 0, completed tasks = 0]
thread: hystrix-MyService-1, input: 9, output: 11
thread: hystrix-MyService-8, input: 5, output: 20
thread: hystrix-MyService-7, input: 8, output: 12
thread: hystrix-MyService-6, input: 17, output: 5
thread: hystrix-MyService-4, input: 12, output: 8
thread: hystrix-MyService-3, input: 18, output: 5
thread: hystrix-MyService-5, input: 7, output: 14
thread: hystrix-MyService-2, input: 11, output: 9
thread: hystrix-MyService-9, input: 14, output: 7
thread: hystrix-MyService-10, input: 13, output: 7
-- after 5 sec --
fallback, thread: main input:2, exception:java.lang.RuntimeException: Hystrix circuit short-circuited and is OPEN
-- after 5 sec --
thread: hystrix-MyService-5, input: 2, output: 50

Example Project

Dependencies and Technologies Used:

  • Spring Boot 2.1.6.RELEASE
    Corresponding Spring Version 5.1.8.RELEASE
  • Spring Cloud Greenwich.SR2
  • spring-boot-starter : Core starter, including auto-configuration support, logging and YAML.
  • spring-cloud-starter-netflix-hystrix 2.1.2.RELEASE: Spring Cloud Starter Netflix Hystrix.
  • JDK 1.8
  • Maven 3.5.4

Circuit Breaker Hystrix concurrent requests Select All Download
  • circuit-breaker-concurrent-requests
    • src
      • main
        • java
          • com
            • logicbig
              • example
                • CircuitBreakerMain.java

    See Also