捕获Hystrix后备抛出的异常?

问题描述 投票:0回答:4

我正在设计服务外观,我有一个方法签名,如下所示:

public Policy getPolicy(long policyId) throws PolicyNotFoundException

如果没有发生任何错误,则返回Policy对象(简单POJO)。如果未找到所请求的策略,则抛出已检查的异常PolicyNotFoundException(仅作为参考 - 当涉及应用程序中的异常处理的最佳实践时,我们遵循this article)。

服务外观层上方的层(在本例中为Spring MVC RestController)知道如何处理此类Policy NotFoundException并返回适当的有效负载。

我试图通过做这样的事情将其合并到HystrixCommand中:

@HystrixCommand(groupKey = "PolicyService", fallbackMethod = "getPolicySafe", ignoreExceptions = { PolicyNotFoundException.class })
public Policy getPolicy(long policyId) throws PolicyNotFoundException {
    LOGGER.info("Getting policy {}", policyId);

    // Simulate some error condition for testing purposes
    throw new RuntimeException("Something happened!");
}

private Policy getPolicySafe(long policyId, Throwable t) throws PolicyNotFoundException {
    LOGGER.warn("Falling back to circuit-breaker for getting policy {}", policyId, t);
    throw new PolicyNotFoundException(policyId);
}

基本上我希望我的断路器只是表现得好像原始查找找不到策略。我遇到的问题虽然是我从fallback方法抛出的异常在某处翻译丢失了。我最终在上面的层中看到的异常是命令方法抛出的RuntimeException,而不是fallback方法抛出的异常。有没有解决的办法?我不想更改原始方法的合同,也不希望上面的图层知道除了在找不到策略的情况下必须捕获PolicyNotFoundException之外的任何内容。此处需要的任何内容都应该在此服务外观层中捕获。

任何和所有的帮助将不胜感激。谢谢!

spring-cloud hystrix spring-cloud-netflix
4个回答
3
投票

所以基于@spencergibb给出的链接 - 我可能在升级到Hystrix 1.5.7之后找到了解决方案。此代码按预期工作

policy rest controller.Java

@RestController
@RequestMapping("/policies")
public class PoliciesApi {
  private static final Logger LOGGER = LoggerFactory.getLogger(PoliciesApi.class);

  @Autowired
  private PolicyService policyService;

  @RequestMapping(value = "/{policyId}", method = RequestMethod.GET, produces = { MediaTypes.POLICY_JSON_VALUE, MediaTypes.POLICY_XML_VALUE })
  public Policy getPolicy(@PathVariable long policyId) {
    try {
      // This just shown for simplicity. There is more to this method (input validation/etc)
      return this.policyService.getPolicy(policyId);
    }
    catch (PolicyNotFoundException ex) {
      // NotFoundException is a RuntimeException annotated with @ResponseStatus(HttpStatus.NOT_FOUND)
      // So the service returns a 404 to the client
      LOGGER.info("Policy {} wasn't found", ex.getPolicyId(), ex);
      throw new NotFoundException(String.format("Policy %s was not found", ex.getPolicyId()));
    }
  }
}

policy service.Java

public interface PolicyService {
    @Cacheable("allPolicies")
    public List<Policy> getPolicies();

    @Cacheable("policies")
    public Policy getPolicy(long policyId) throws PolicyNotFoundException;
}

policy service imp了.Java:

@Service
public class PolicyServiceImpl implements PolicyService {
  @HystrixCommand(groupKey = "PolicyService", fallbackMethod = "getPolicySafe", ignoreExceptions = { PolicyNotFoundException.class })
  public Policy getPolicy(long policyId) throws PolicyNotFoundException {
    LOGGER.info("Getting policy {}", policyId);

    // Simulate some error condition for testing purposes
    throw new RuntimeException("Something happened!");
  }

  @HystrixCommand(groupKey = "PolicyService", ignoreExceptions = { PolicyNotFoundException.class }, raiseHystrixExceptions = { HystrixException.RUNTIME_EXCEPTION })
  private Policy getPolicySafe(long policyId) throws PolicyNotFoundException {
    // Here is we hit our fallback we want to log a warning & simply act as if the policy wasn't found by throwing the same contingency exception as the API does
    LOGGER.warn("Falling back to circuit-breaker for getting policy {}", policyId);

    throw new PolicyNotFoundException(policyId);
  }
}

1
投票

虽然你的解决方案可能适合你,但我注意到你的代码有些奇怪(我无法检查我的假设,所以我想请你检查一下)。

  1. 尽量避免在代码中使用已检查的异常,因为维护起来很难。
  2. 根据您的代码,您将永远不会捕获“PolicyNotFoundException”,因为您正在使用raiseHystrixExceptions = {HystrixException.RUNTIME_EXCEPTION},这意味着您将不会获取自定义异常,以便传播HystrixRuntimeException。尝试按如下方式重写代码,这样可以简化代码并修复一些问题:

@Service
public class PolicyServiceImpl implements PolicyService {
  @HystrixCommand(groupKey = "PolicyService", fallbackMethod = "getPolicySafe")
  public Policy getPolicy(long policyId) throws PolicyNotFoundException {
    LOGGER.info("Getting policy {}", policyId);
    throw new PolicyNotFoundException(); // throw real PolicyNotFoundException if policy is absent for the given id
  }

  @HystrixCommand(groupKey = "PolicyService")
  private Policy getPolicySafe(long policyId) throws PolicyNotFoundException {
    // Here is we hit our fallback we want to log a warning & simply act as if the policy wasn't found by throwing the same contingency exception as the API does
    LOGGER.warn("Falling back to circuit-breaker for getting policy {}", policyId);

    throw new PolicyNotFoundException(policyId);
  }
}

1
投票

这是hystrix的默认行为。 “如果命令有一个后备,那么只有第一个例外,即trigers回退逻辑将传播给调用者”

请参阅错误传播部分here


0
投票

我这样做:

@Component
public class HystrixClient {

  @HystrixCommand(ignoreExceptions = {ClientArgumentException.class})
  public POJO getPojo(String id)
        throws ClientNoDataFoundException, ClientArgumentException, ClientGeneralException {

    //call my service and return POJO
  }
}

@Component
public TrueClientUsedForAnotherSerivce {

  @Autowired
  HystrixClient hystrixClient;

 public POJO getPojo(String id)
        throws ClientNoDataFoundException, ClientArgumentException, ClientGeneralException, ClientOpenCircuitException {
    try {           
        POJO result = hystrixClient.getCellular(id);            

        return result;
    }
    catch(HystrixRuntimeException e) {
        LOG.debug("The circuit is open");
        throw new ClientOpenCircuitException("Open circuit");
    }
}   

它只适用于@HystrixCommand方法在另一个类中。

© www.soinside.com 2019 - 2024. All rights reserved.