You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Hystrix超时后run()仍执行,如何返回后续请求响应?

How to Return the Late Response After Hystrix Timeout Triggers Fallback?

Problem Statement

I've created a class by inheriting HystrixCommand, configured request timeout using HystrixCommandProperties.Setter().withExecutionIsolationThreadTimeoutInMilliseconds(int milliSec), and overridden the fallback method that triggers on timeout. Here's my code:

@Override
protected JSONObject run() throws Exception {
    // Execute HTTP call
    final HttpEntity<String> httpEntity = new HttpEntity<>(httpHeaders);
    ResponseEntity<String> response = restTemplate.exchange(requestUrl, HttpMethod.GET, httpEntity, JSONObject.class)
            .getBody();
    System.out.println(response);
    return response;
}

@Override
protected JSONObject getFallback() {
    final JSONObject json = new JSONObject();
    json.put("status", "900");
    json.put("message", "Request Failed");
    return json;
}

When a timeout occurs, the fallback response is returned as expected. However, I noticed that the HTTP request executed in run() still returns a response later, and I have no way to return this late response to the client. Is there any way to handle and return this subsequent response?


Solution Options

Since HTTP follows a strict request-response model, once you've sent the fallback response to the client, you can't modify that response to include the late-arriving result. But you can handle the late response in background processes, or use asynchronous communication to notify the client later. Here are two practical approaches:

1. Async Execution with Background Processing

Modify the run() method to execute the HTTP call asynchronously. This way, when the timeout triggers the fallback, the async task continues running in the background. You can then process the late response (e.g., cache it, log it, or store it in a database) and optionally notify the client via an asynchronous channel.

@Override
protected JSONObject run() throws Exception {
    // Wrap the HTTP call in an async task
    CompletableFuture<JSONObject> requestFuture = CompletableFuture.supplyAsync(() -> {
        try {
            final HttpEntity<String> httpEntity = new HttpEntity<>(httpHeaders);
            ResponseEntity<String> rawResponse = restTemplate.exchange(requestUrl, HttpMethod.GET, httpEntity, String.class);
            JSONObject response = new JSONObject(rawResponse.getBody());
            // Handle the late response here (e.g., cache, log, or trigger a notification)
            processLateResponse(response);
            return response;
        } catch (Exception e) {
            throw new RuntimeException("HTTP call failed", e);
        }
    });

    try {
        // Wait for the result within the Hystrix timeout window
        return requestFuture.get(
            getProperties().getExecutionIsolationThreadTimeoutInMilliseconds(),
            TimeUnit.MILLISECONDS
        );
    } catch (TimeoutException e) {
        // Timeout triggers fallback, but the async task keeps running
        throw new HystrixTimeoutException();
    }
}

// Method to handle the late-arriving response
private void processLateResponse(JSONObject response) {
    // Example: Store in cache for client polling
    cache.put("late-response-key", response);
    // Or send a WebSocket/SSE message to the client if connected
    // websocketService.sendUpdate(response);
    System.out.println("Late response processed: " + response);
}

How this works:

  • The HTTP call runs in a separate thread via CompletableFuture.supplyAsync().
  • The main thread waits for the result only within the Hystrix timeout period. If it times out, it throws HystrixTimeoutException to trigger the fallback.
  • The async task continues executing, and when the response arrives, processLateResponse() handles it. If you need to get this to the client, you can use:
    • Client polling: Let the client periodically check a cache endpoint for the updated result.
    • WebSocket/SSE: Push the result to the client in real-time if they're connected.

2. Use HystrixObservableCommand for Multi-Result Emission

If your client can handle multiple responses (e.g., using streaming or event-driven clients), you can switch to HystrixObservableCommand instead of HystrixCommand. This allows you to emit both the fallback response and the late-arriving result.

public class MyObservableHystrixCommand extends HystrixObservableCommand<JSONObject> {
    private String requestUrl;
    private HttpHeaders httpHeaders;
    private RestTemplate restTemplate;

    // Constructor with necessary dependencies
    public MyObservableHystrixCommand(String requestUrl, HttpHeaders httpHeaders, RestTemplate restTemplate) {
        super(HystrixCommandGroupKey.Factory.asKey("MyGroup"));
        this.requestUrl = requestUrl;
        this.httpHeaders = httpHeaders;
        this.restTemplate = restTemplate;
    }

    @Override
    protected Observable<JSONObject> construct() {
        return Observable.create(subscriber -> {
            // Async HTTP call
            CompletableFuture.runAsync(() -> {
                try {
                    final HttpEntity<String> httpEntity = new HttpEntity<>(httpHeaders);
                    ResponseEntity<String> rawResponse = restTemplate.exchange(requestUrl, HttpMethod.GET, httpEntity, String.class);
                    JSONObject response = new JSONObject(rawResponse.getBody());
                    subscriber.onNext(response);
                    subscriber.onCompleted();
                } catch (Exception e) {
                    subscriber.onError(e);
                }
            });
        }).timeout(getProperties().getExecutionIsolationThreadTimeoutInMilliseconds(), TimeUnit.MILLISECONDS);
    }

    @Override
    protected Observable<JSONObject> resumeWithFallback() {
        // Create fallback response
        JSONObject fallback = new JSONObject();
        fallback.put("status", "900");
        fallback.put("message", "Request Failed");
        
        // Emit fallback first, then merge with the original observable (if it completes later)
        return Observable.just(fallback)
                .mergeWith(construct().onErrorResumeNext(Observable.empty()));
    }
}

How this works:

  • The construct() method creates an Observable that emits the HTTP response when it arrives.
  • The resumeWithFallback() method emits the fallback immediately on timeout, then merges with the original Observable to emit the late response if it eventually completes.
  • Your client needs to subscribe to this Observable and handle both the fallback and the late response (e.g., using RxJava or a streaming client).

Key Takeaways

  • You can't modify an already sent HTTP response to include a late result, but you can process the result in the background.
  • For client-facing updates, use asynchronous communication patterns like WebSocket/SSE or client-side polling.
  • HystrixObservableCommand is useful if you need to emit multiple results, but it requires changes to both your server and client code.

内容的提问来源于stack exchange,提问作者Arunkumar Papena

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 04:25:25