1515import static com .tencent .trpc .core .common .Constants .DEFAULT_CLIENT_REQUEST_TIMEOUT_MS ;
1616import static com .tencent .trpc .proto .http .common .HttpConstants .CONNECTION_REQUEST_TIMEOUT ;
1717
18- import autovalue .shaded .com .google .common .common .base .Objects ;
1918import com .tencent .trpc .core .common .config .BackendConfig ;
2019import com .tencent .trpc .core .common .config .ConsumerConfig ;
2120import com .tencent .trpc .core .common .config .ProtocolConfig ;
2928import java .nio .charset .StandardCharsets ;
3029import java .util .HashMap ;
3130import java .util .Map ;
31+ import java .util .Objects ;
3232import java .util .concurrent .Future ;
3333import java .util .concurrent .TimeUnit ;
3434import org .apache .hc .client5 .http .async .methods .SimpleHttpRequest ;
4444
4545/**
4646 * HTTP/2 protocol client invoker, supporting both h2 and http2c.
47+ *
48+ * <p>Each {@link #send(Request)} entry signals the underlying {@link Http2cRpcClient} that
49+ * it is being used (drives the idle-eviction heuristic) and reports success / failure to
50+ * drive the consecutive-failure counter that flips the client to unavailable on sustained
51+ * backend outages.</p>
4752 */
4853public class Http2ConsumerInvoker <T > extends AbstractConsumerInvoker <T > {
4954
@@ -60,19 +65,38 @@ public Http2ConsumerInvoker(Http2cRpcClient client, ConsumerConfig<T> config,
6065 *
6166 * @param request client request
6267 * @return Response
63- * @throws Exception if send request failed
68+ * @throws Exception declared to honour the abstract contract; the implementation never
69+ * lets exceptions escape — every failure path is wrapped into a Response with
70+ * {@code exception != null}.
6471 */
6572 @ Override
6673 public Response send (Request request ) throws Exception {
74+ Http2cRpcClient http2cRpcClient = (Http2cRpcClient ) client ;
75+ // Mark "used" before any work so even a failed request keeps the idle-eviction timer
76+ // accurate (a failing client is still actively used and must not be reaped as orphan).
77+ http2cRpcClient .markUsed ();
78+
6779 int requestTimeout = config .getBackendConfig ().getRequestTimeout ();
68- SimpleHttpRequest simpleHttpRequest = buildRequest (request , requestTimeout );
80+ SimpleHttpRequest simpleHttpRequest ;
81+ try {
82+ simpleHttpRequest = buildRequest (request , requestTimeout );
83+ } catch (Exception ex ) {
84+ http2cRpcClient .markFailure ();
85+ return RpcUtils .newResponse (request , null , ex );
86+ }
6987
7088 try {
7189 SimpleHttpResponse simpleHttpResponse = execute (request , requestTimeout ,
72- simpleHttpRequest );
73-
74- return handleResponse (request , simpleHttpResponse );
90+ simpleHttpRequest , http2cRpcClient );
91+ Response response = handleResponse (request , simpleHttpResponse );
92+ if (response .getException () == null ) {
93+ http2cRpcClient .markSuccess ();
94+ } else {
95+ http2cRpcClient .markFailure ();
96+ }
97+ return response ;
7598 } catch (Exception e ) {
99+ http2cRpcClient .markFailure ();
76100 return RpcUtils .newResponse (request , null , e );
77101 }
78102
@@ -132,15 +156,12 @@ private Response handleResponse(Request request, SimpleHttpResponse simpleHttpRe
132156 * @param request TRPC request
133157 * @param requestTimeout request timeout
134158 * @param simpleHttpRequest HTTP request
159+ * @param http2cRpcClient already-resolved owning client (avoids a redundant cast)
135160 * @return HTTP response
136161 * @throws Exception if do HTTP request failed
137162 */
138163 private SimpleHttpResponse execute (Request request , int requestTimeout ,
139- SimpleHttpRequest simpleHttpRequest ) throws Exception {
140- Http2cRpcClient http2cRpcClient = (Http2cRpcClient ) client ;
141- // Refresh idle counter so the cluster manager's reconnect-check timer keeps treating
142- // this client as healthy while it's actively serving requests.
143- http2cRpcClient .markUsed ();
164+ SimpleHttpRequest simpleHttpRequest , Http2cRpcClient http2cRpcClient ) throws Exception {
144165 CloseableHttpAsyncClient httpAsyncClient = http2cRpcClient .getHttpAsyncClient ();
145166 Future <SimpleHttpResponse > httpResponseFuture = httpAsyncClient .execute (simpleHttpRequest ,
146167 new FutureCallback <SimpleHttpResponse >() {
@@ -210,7 +231,7 @@ private SimpleHttpRequest buildRequest(Request request, int requestTimeout) thro
210231 }
211232 // Set custom business headers, consistent with the TRPC protocol, only process String and byte[]
212233 request .getAttachments ().forEach ((k , v ) -> {
213- if (Objects .equal (k , HttpHeaders .TRANSFER_ENCODING ) || Objects .equal (k , HttpHeaders .CONTENT_LENGTH )) {
234+ if (Objects .equals (k , HttpHeaders .TRANSFER_ENCODING ) || Objects .equals (k , HttpHeaders .CONTENT_LENGTH )) {
214235 return ;
215236 }
216237 if (v instanceof String ) {
0 commit comments