Итак, прежде всего, поскольку внутренне Hystrix
использует ThreadPoolExecutor
(потоки созданы один раз и используются повторно), поэтому неправильно использовать InheritableThreadLocal
.
Из вышеприведенного вопроса и того, что вы задали в моем блоге , я понимаю, что ваша проблема
InheritableThreadLocal
становится нулевым в резервном методе Hystrix
Дальнейшее дополнение к этому (вы можете проверить это)
InheritableThreadLocal
становится нулевым в методе резервирования Hystrix только в случае тайм-аутов, а не в случае каких-либо других исключений
Я бы порекомендовал другим обратиться к моему блогу . Откат Hystrix в случае таймаута происходит в потоке таймера Hystrix.
Резервный поток выполнения Hystrix
Вы можете убедиться в этом, войдя в систему Thread.currentThread().getName()
Поскольку родительский элемент hystrix-timer thread
не является вашим вызывающим потоком, и поэтому ваш TranstableThreadLocal.get () становится нулевым.
Для решения этой проблемы я бы рекомендовал использовать HystrixCommandExecutionHook и HystrixRequestVariableDefault . Используя это, вы можете реализовать хуки типа onStart, onExecutionStart, onFallbackStart
и т. Д., В которых вам нужно получить / установить переменные threadLocal. Для более подробной информации вы можете обратиться к последнему разделу в блоге.
Обновление:
Для вашего случая использования вы можете изменить свой код следующим образом:
ThreadLocalUtil.java
public class ThreadLocalUtil {
private static ThreadLocal<ConcurrentHashMap<String, Object>> transmittableThreadLocal = new ThreadLocal<>();
public static ConcurrentHashMap<String, Object> getThreadLocalData() {
return transmittableThreadLocal.get();
}
public static void setThreadLocalData(ConcurrentHashMap<String, Object> data) {
transmittableThreadLocal.set(data);
}
public static void addDataToThreadLocalMap(String key, Object value) {
Map<String, Object> existingDataMap = transmittableThreadLocal.get();
if (value != null) {
existingDataMap.put(key, value);
}
}
public static Object getDataFromThreadLocalMap(String key) {
Map<String, Object> existingDataMap = transmittableThreadLocal.get();
return existingDataMap.get(key);
}
public static void clearThreadLocalDataMap() {
if (transmittableThreadLocal != null)
transmittableThreadLocal.remove();
}
public static Object getRequestData(String key) {
Map<String, Object> existingDataMap = transmittableThreadLocal.get();
if (existingDataMap != null) {
return existingDataMap.get(key);
}
return "-1";
}
public static void initThreadLocals() {
transmittableThreadLocal.set(new ConcurrentHashMap<>());
String requestId = "REQUEST_ID_" + System.currentTimeMillis();
addDataToThreadLocalMap("REQUEST_ID", requestId);
}
}
EmployeeService.java
@Component
public abstract class EmployeeService {
public abstract void getEmployee(int employeeId);
public void fallbackMethod(int employeeid) {
threadLocalUtil.addDataToThreadLocalMap("ErrorResponse", "Fallback response:: No employee details available temporarily");
}
}
EmployeeServiceImpl.java
@Service
public class EmployeeServiceImpl extends EmployeeService {
@HystrixCommand(fallbackMethod = "fallbackMethod", commandProperties = {
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "900"),
@HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "10") })
public void getEmployee(int employeeId) {
System.out.println("Getting Employee details for " + employeeId + ", threadLocalUtil : " + threadLocalUtil.getDataFromThreadLocalMap("EMPLOYEE_ID"));
String response = restTemplate.exchange("http://localhost:8011/findEmployeeDetails/{employeeid}",
HttpMethod.GET, null, new ParameterizedTypeReference<String>() {
}, employeeId).getBody();
threadLocalUtil.addDataToThreadLocalMap("Response", response);
}
@Autowired
RestTemplate restTemplate;
}
HystrixHook.java
public class HystrixHook extends HystrixCommandExecutionHook {
private HystrixRequestVariableDefault<ConcurrentHashMap<String, Object>> hrv = new HystrixRequestVariableDefault<>();
@Override
public <T> void onStart(HystrixInvokable<T> commandInstance) {
HystrixRequestContext.initializeContext();
getThreadLocals();
}
@Override
public <T> void onExecutionStart(HystrixInvokable<T> commandInstance) {
setThreadLocals();
}
@Override
public <T> void onFallbackStart(HystrixInvokable<T> commandInstance) {
setThreadLocals();
}
@Override
public <T> void onSuccess(HystrixInvokable<T> commandInstance) {
HystrixRequestContext.getContextForCurrentThread().shutdown();
super.onSuccess(commandInstance);
}
@Override
public <T> Exception onError(HystrixInvokable<T> commandInstance, HystrixRuntimeException.FailureType failureType, Exception e) {
HystrixRequestContext.getContextForCurrentThread().shutdown();
return super.onError(commandInstance, failureType, e);
}
private void getThreadLocals() {
hrv.set(ThreadLocalUtil.getThreadLocalData());
}
private void setThreadLocals() {
ThreadLocalUtil.setThreadLocalData(hrv.get());
}
}
AbcApplication.java
public class AbcApplication {
public static void main(String[] args) {
HystrixPlugins.getInstance().registerCommandExecutionHook(new HystrixHook());
SpringApplication.run(Abc.class, args);
}
}
Надеюсь, это поможет