Search code examples
grpcgrpc-javacircuit-breaker

Circuit Breaker with gRPC


In a REST service adding a circuit breaker with hystrix, I could do the following:

@HystrixCommand(fallbackMethod = "getBackupResult")
@GetMapping(value = "/result")
public ResponseEntity<ResultDto> getResult(@RequestParam("request") String someRequest) {

    ResultDto resultDto = service.parserRequest(someRequest);
    return new ResponseEntity<>(resultDto, HttpStatus.OK);
}

public ResponseEntity<ResultDto> getBackupResult(@RequestParam("request") String someRequest) {

    ResultDto resultDto = new ResultDto();
    return new ResponseEntity<>(resultDto, HttpStatus.OK);
}

Is there something similar I can do for the gRPC call?

public void parseRequest(ParseRequest request, StreamObserver<ParseResponse> responseObserver) {
    try {
        ParseResponse parseResponse  = service.parseRequest(request.getSomeRequest());

        responseObserver.onNext(parseResponse);
        responseObserver.onCompleted();
    } catch (Exception e) {
        logger.error("Failed to execute parse request.", e);
        responseObserver.onError(new StatusException(Status.INTERNAL));
    }
}

Solution

  • I solved my problem by implementing the circuit-breaker on my client. I used the sentinel library

    To react on exceptions ratio for example I added this rule:

        private static final String KEY = "callGRPC";
    
        private void callGRPC(List<String> userAgents) {
            initDegradeRule();
            ManagedChannel channel = ManagedChannelBuilder.forAddress(grpcHost, grpcPort).usePlaintext()
                                                          .build();
            for (String userAgent : userAgents) {
                Entry entry = null;
                try {
                    entry = SphU.entry(KEY);
                    UserAgentServiceGrpc.UserAgentServiceBlockingStub stub
                            = UserAgentServiceGrpc.newBlockingStub(channel);
                    UserAgentParseRequest request = UserAgentRequest.newBuilder().setUserAgent(userAgent).build();
                    UserAgentResponse userAgentResponse = stub.getUserAgentDetails(request);
                } catch (BlockException e) {
                    logger.error("Circuit-breaker is on and the call has been blocked");
                } catch (Throwable t) {
                    logger.error("Exception was thrown", t);
                } finally {
                    if (entry != null) {
                        entry.exit();
                    }
                }
            }
            channel.shutdown();
        }
    
        private void initDegradeRule() {
            List<DegradeRule> rules = new ArrayList<DegradeRule>();
            DegradeRule rule = new DegradeRule();
            rule.setResource(KEY);
            rule.setCount(0.5);
            rule.setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_RATIO);
            rule.setTimeWindow(60);
            rules.add(rule);
            DegradeRuleManager.loadRules(rules);
        }