Close

Spring Cloud - Circuit Breaker Hystrix, Changing Default Thread Pool Properties

[Last Updated: Aug 11, 2020]

The Hystrix Circuit breaker's thread pool properties can be changed by one of the followings

  1. By using @HystrixCommand#threadPoolProperties
  2. By defining @HystrixCommand#threadPoolKey and referencing that in application.properties via
    hystrix.threadpool.<myThreadPoolKey>.<propertyName>=value
  3. By using hystrix.threadpool.default.<propertyName>=value in the application properties which will change the property on default level.

Example

By using @HystrixCommand#threadPoolKey

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", threadPoolKey = "myThreadPool")
  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);
  }
}

src/main/resources/application.properties

hystrix.threadpool.myThreadPool.coreSize=5
hystrix.threadpool.myThreadPool.maxQueueSize=-1
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(CircuitBreakerMain2.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(5);

      TimeUnit.SECONDS.sleep(5);
      System.out.println("-- after 5 sec --");
      myService.doSomething(2);
  }
}
Main Thread: main
-- calling doSomething(1) 20 times --
fallback, thread: pool-1-thread-4 input:4, exception:java.util.concurrent.RejectedExecutionException: Task java.util.concurrent.FutureTask@37519ff0 rejected from java.util.concurrent.ThreadPoolExecutor@781fbff7[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@49de987f rejected from java.util.concurrent.ThreadPoolExecutor@781fbff7[Running, pool size = 5, active threads = 5, queued tasks = 0, completed tasks = 0]
fallback, thread: pool-1-thread-7 input:7, exception:java.util.concurrent.RejectedExecutionException: Task java.util.concurrent.FutureTask@613d3e99 rejected from java.util.concurrent.ThreadPoolExecutor@781fbff7[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@250ac271 rejected from java.util.concurrent.ThreadPoolExecutor@781fbff7[Running, pool size = 5, active threads = 5, queued tasks = 0, completed tasks = 0]
fallback, thread: pool-1-thread-3 input:3, exception:java.util.concurrent.RejectedExecutionException: Task java.util.concurrent.FutureTask@2f06d8f rejected from java.util.concurrent.ThreadPoolExecutor@781fbff7[Running, pool size = 5, active threads = 5, queued tasks = 0, completed tasks = 0]
fallback, thread: pool-1-thread-11 input:11, exception:java.util.concurrent.RejectedExecutionException: Task java.util.concurrent.FutureTask@1b2824dc rejected from java.util.concurrent.ThreadPoolExecutor@781fbff7[Running, pool size = 4, active threads = 4, queued tasks = 0, completed tasks = 0]
fallback, thread: pool-1-thread-20 input:20, exception:java.util.concurrent.RejectedExecutionException: Task java.util.concurrent.FutureTask@1ffae16c rejected from java.util.concurrent.ThreadPoolExecutor@781fbff7[Running, pool size = 4, active threads = 4, queued tasks = 0, completed tasks = 0]
fallback, thread: pool-1-thread-2 input:2, exception:java.util.concurrent.RejectedExecutionException: Task java.util.concurrent.FutureTask@225f0f1 rejected from java.util.concurrent.ThreadPoolExecutor@781fbff7[Running, pool size = 5, active threads = 5, queued tasks = 0, completed tasks = 0]
fallback, thread: pool-1-thread-10 input:10, exception:java.util.concurrent.RejectedExecutionException: Task java.util.concurrent.FutureTask@177f0eaf rejected from java.util.concurrent.ThreadPoolExecutor@781fbff7[Running, pool size = 5, active threads = 5, queued tasks = 0, completed tasks = 0]
fallback, thread: pool-1-thread-12 input:12, exception:java.util.concurrent.RejectedExecutionException: Task java.util.concurrent.FutureTask@63973405 rejected from java.util.concurrent.ThreadPoolExecutor@781fbff7[Running, pool size = 4, active threads = 4, queued tasks = 0, completed tasks = 0]
thread: hystrix-myThreadPool-2, input: 8, output: 12
fallback, thread: pool-1-thread-9 input:9, exception:java.util.concurrent.RejectedExecutionException: Task java.util.concurrent.FutureTask@7dfc7c1 rejected from java.util.concurrent.ThreadPoolExecutor@781fbff7[Running, pool size = 4, active threads = 4, queued tasks = 0, completed tasks = 0]
fallback, thread: pool-1-thread-1 input:1, exception:java.util.concurrent.RejectedExecutionException: Task java.util.concurrent.FutureTask@6181eae3 rejected from java.util.concurrent.ThreadPoolExecutor@781fbff7[Running, pool size = 5, active threads = 5, queued tasks = 0, completed tasks = 0]
fallback, thread: pool-1-thread-14 input:14, exception:java.util.concurrent.RejectedExecutionException: Task java.util.concurrent.FutureTask@4b0ca2eb rejected from java.util.concurrent.ThreadPoolExecutor@781fbff7[Running, pool size = 5, active threads = 5, queued tasks = 0, completed tasks = 0]
thread: hystrix-myThreadPool-3, input: 17, output: 5
thread: hystrix-myThreadPool-1, input: 6, output: 16
thread: hystrix-myThreadPool-5, input: 13, output: 7
thread: hystrix-myThreadPool-4, input: 19, output: 5
-- after 5 sec --
fallback, thread: main input:5, exception:java.lang.RuntimeException: Hystrix circuit short-circuited and is OPEN
-- after 5 sec --
thread: hystrix-myThreadPool-5, input: 2, output: 50

By using @HystrixCommand#threadPoolProperties

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",
          threadPoolProperties = {
                  @HystrixProperty(name = "coreSize", value = "3"),
                  @HystrixProperty(name = "maxQueueSize", value = "-1"),
          }
  )
  public void doSomething2(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);
  }
}
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 CircuitBreakerMain2 {
  public static void main(String[] args) throws InterruptedException {
      ConfigurableApplicationContext ctx = SpringApplication.run(CircuitBreakerMain2.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.doSomething2(finalI +1)
          );
      }
      es.shutdown();
      es.awaitTermination(10, TimeUnit.SECONDS);

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

      TimeUnit.SECONDS.sleep(5);
      System.out.println("-- after 5 sec --");
      myService.doSomething2(2);
  }
}
Main Thread: main
-- calling doSomething(1) 20 times --
fallback, thread: pool-1-thread-13 input:13, exception:java.util.concurrent.RejectedExecutionException: Task java.util.concurrent.FutureTask@3d3f38bd rejected from java.util.concurrent.ThreadPoolExecutor@8071d4b[Running, pool size = 3, active threads = 3, queued tasks = 0, completed tasks = 0]
fallback, thread: pool-1-thread-5 input:5, exception:java.util.concurrent.RejectedExecutionException: Task java.util.concurrent.FutureTask@283acf48 rejected from java.util.concurrent.ThreadPoolExecutor@8071d4b[Running, pool size = 3, active threads = 3, queued tasks = 0, completed tasks = 0]
fallback, thread: pool-1-thread-11 input:11, exception:java.util.concurrent.RejectedExecutionException: Task java.util.concurrent.FutureTask@76ca1198 rejected from java.util.concurrent.ThreadPoolExecutor@8071d4b[Running, pool size = 3, active threads = 3, queued tasks = 0, completed tasks = 0]
fallback, thread: pool-1-thread-1 input:1, exception:java.util.concurrent.RejectedExecutionException: Task java.util.concurrent.FutureTask@6a9f0098 rejected from java.util.concurrent.ThreadPoolExecutor@8071d4b[Running, pool size = 3, active threads = 3, queued tasks = 0, completed tasks = 0]
fallback, thread: pool-1-thread-8 input:8, exception:java.util.concurrent.RejectedExecutionException: Task java.util.concurrent.FutureTask@523588a6 rejected from java.util.concurrent.ThreadPoolExecutor@8071d4b[Running, pool size = 3, active threads = 3, queued tasks = 0, completed tasks = 0]
fallback, thread: pool-1-thread-12 input:12, exception:java.util.concurrent.RejectedExecutionException: Task java.util.concurrent.FutureTask@7a863ec5 rejected from java.util.concurrent.ThreadPoolExecutor@8071d4b[Running, pool size = 3, active threads = 3, queued tasks = 0, completed tasks = 0]
fallback, thread: pool-1-thread-18 input:18, exception:java.util.concurrent.RejectedExecutionException: Task java.util.concurrent.FutureTask@75ae096c rejected from java.util.concurrent.ThreadPoolExecutor@8071d4b[Running, pool size = 3, active threads = 3, queued tasks = 0, completed tasks = 0]
fallback, thread: pool-1-thread-15 input:15, exception:java.util.concurrent.RejectedExecutionException: Task java.util.concurrent.FutureTask@476dc3d6 rejected from java.util.concurrent.ThreadPoolExecutor@8071d4b[Running, pool size = 3, active threads = 3, queued tasks = 0, completed tasks = 0]
fallback, thread: pool-1-thread-14 input:14, exception:java.util.concurrent.RejectedExecutionException: Task java.util.concurrent.FutureTask@2990a096 rejected from java.util.concurrent.ThreadPoolExecutor@8071d4b[Running, pool size = 3, active threads = 3, queued tasks = 0, completed tasks = 0]
fallback, thread: pool-1-thread-7 input:7, exception:java.util.concurrent.RejectedExecutionException: Task java.util.concurrent.FutureTask@64855f90 rejected from java.util.concurrent.ThreadPoolExecutor@8071d4b[Running, pool size = 3, active threads = 3, queued tasks = 0, completed tasks = 0]
fallback, thread: pool-1-thread-17 input:17, exception:java.util.concurrent.RejectedExecutionException: Task java.util.concurrent.FutureTask@5a1c6aea rejected from java.util.concurrent.ThreadPoolExecutor@8071d4b[Running, pool size = 3, active threads = 3, queued tasks = 0, completed tasks = 0]
thread: hystrix-MyService-3, input: 20, output: 5
thread: hystrix-MyService-1, input: 6, output: 16
thread: hystrix-MyService-2, input: 3, output: 33
-- after 5 sec --
fallback, thread: main input:5, exception:java.lang.RuntimeException: Hystrix circuit short-circuited and is OPEN
-- after 5 sec --
thread: hystrix-MyService-1, 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

Hystrix - Changing default Thread Pool Properties Select All Download
  • circuit-breaker-thread-pool-config
    • src
      • main
        • java
          • com
            • logicbig
              • example
                • MyService.java
          • resources

    See Also