Resolving OpenFeign Asynchronous Call Failures by Propagating Request Context
This article explains why OpenFeign asynchronous calls fail due to lost request context, demonstrates a RequestInterceptor to propagate JWT tokens, and shows how to capture and set RequestAttributes in CompletableFuture tasks so that async Feign calls succeed without triggering Sentinel degradation.
Recently a reader asked why OpenFeign asynchronous calls always fail and trigger Sentinel degradation, while synchronous calls work fine.
The provided code shows two CompletableFuture tasks invoking feign.remoteCall() asynchronously, which leads to failure because the request context (e.g., JWT token) is lost when the call runs in a different thread.
The root cause is that Feign calls lose the thread‑local request information stored by RequestContextHolder , so the token cannot be forwarded to the remote service.
A common fix is to create a RequestInterceptor that copies the original request headers into the Feign RequestTemplate before the call is executed.
@Component
@Slf4j
public class FeignRequestInterceptor implements RequestInterceptor {
@Override
public void apply(RequestTemplate template) {
HttpServletRequest httpServletRequest = RequestContextUtils.getRequest();
Map<String, String> headers = getHeaders(httpServletRequest);
for (Map.Entry<String, String> entry : headers.entrySet()) {
template.header(entry.getKey(), entry.getValue());
}
}
/**
* 获取原请求头
*/
private Map<String, String> getHeaders(HttpServletRequest request) {
Map<String, String> map = new LinkedHashMap<>();
Enumeration<String> enumeration = request.getHeaderNames();
if (enumeration != null) {
while (enumeration.hasMoreElements()) {
String key = enumeration.nextElement();
String value = request.getHeader(key);
if (StrUtil.equals(OAuthConstant.TOKEN_NAME,key)){
map.put(key, value);
break;
}
}
}
return map;
}
}The interceptor extracts the token (or other needed headers) from the incoming HttpServletRequest and adds them to the Feign request, ensuring the downstream service receives the authentication information.
Because RequestContextHolder stores request data in a ThreadLocal , it is only available to the thread that originally handled the HTTP request.
To make asynchronous calls work, capture the parent thread’s RequestAttributes before launching the async task and set them inside each async thread.
//获取主线程的请求信息
RequestAttributes attributes = RequestContextHolder.getRequestAttributes();
CompletableFuture<T> future1 = CompletableFuture.supplyAsync(() -> {
//将主线程的请求信息设置到异步线程中,否则会丢失请求上下文,导致调用失败
RequestContextHolder.setRequestAttributes(attributes);
//openfeign的调用
return feign.remoteCall();
}, executor);
CompletableFuture<T> future2 = CompletableFuture.supplyAsync(() -> {
//将主线程的请求信息设置到异步线程中,否则会丢失请求上下文,导致调用失败
RequestContextHolder.setRequestAttributes(attributes);
//openfeign的调用
return feign.remoteCall();
}, executor);
CompletableFuture.allOf(future1, future2).join();After propagating the request attributes, the OpenFeign asynchronous calls succeed without triggering Sentinel degradation.
IT Services Circle
Delivering cutting-edge internet insights and practical learning resources. We're a passionate and principled IT media platform.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.