【问题标题】:Q: Using Circuit Breaker in SAP Cloud SDK resilience问:在 SAP Cloud SDK 弹性中使用断路器
【发布时间】:2020-04-21 17:28:17
【问题描述】:

当我尝试使用 ResilienceDecorator.executeCallable() 来启用断路器时,我必须在我的可调用对象中抛出 ResilienceRuntimeException 以使断路器工作。示例代码如下。没有它,断路器总是闭合的。这是正确的方法吗?

response = ResilienceDecorator.executeCallable(() -> {
    HttpResponse response1 = tryHttpClient.get().execute(request);
    if (response1.getStatusLine().getStatusCode() == 404){
      throw new ResilienceRuntimeException("404 error is raised when calling SB api");
    }
    return response1;
  },
          ResilienceConfiguration.of(SubscriptionBillingAdapter.class).isolationMode(ResilienceIsolationMode.TENANT_OPTIONAL).timeLimiterConfiguration(ResilienceConfiguration.TimeLimiterConfiguration.of().timeoutDuration(Duration.ofSeconds(6L))).circuitBreakerConfiguration(ResilienceConfiguration.CircuitBreakerConfiguration.of().waitDuration(Duration.ofSeconds(600000L)).failureRateThreshold(1).closedBufferSize(1).halfOpenBufferSize(1)),
          e -> {LOG.warn("resiliience fallback call: " + e); return response1;});

我在问,因为我没有看到它的任何文件。此外,当我检查如何检索 SCP 中的目标配置时,我在 com.sap.cloud.sdk.cloudplatform.connectivity.DestinationService 中看到了以下代码。当使用 ResilienceDecorator.executeCallable() 时,它不会抛出 ResilienceRuntimeException。所以我的问题是我需要抛出 ResilienceRuntimeException 还是不让断路器工作?如果我不需要,我的代码有什么问题吗?

return (String)ResilienceDecorator.executeCallable(() -> {
            XsuaaCredentials xsuaaCredentials = (new ServiceCredentialsRetriever()).getClientCredentials("destination");
            AccessToken accessToken;
            if (propagateUser) {
                accessToken = xsuaaService.retrieveAccessTokenViaUserTokenExchange(xsuaaCredentials.getXsuaaUri(), xsuaaCredentials.getCredentials(), useProviderTenant);
            } else {
                accessToken = xsuaaService.retrieveAccessTokenViaClientCredentialsGrant(xsuaaCredentials.getXsuaaUri(), xsuaaCredentials.getCredentials(), useProviderTenant);
            }

            return this.fetchDestinationsJson(servicePath, accessToken);
        }, ResilienceConfiguration.of(DestinationService.class).isolationMode(ResilienceIsolationMode.TENANT_OPTIONAL).timeLimiterConfiguration(TimeLimiterConfiguration.of().timeoutDuration(Duration.ofSeconds(6L))).circuitBreakerConfiguration(CircuitBreakerConfiguration.of().waitDuration(Duration.ofSeconds(6L))));

【问题讨论】:

    标签: connectivity circuit-breaker sap-cloud-sdk


    【解决方案1】:

    史蒂文

    我在这方面不是最有经验的,但是看看你的代码我觉得很好。当服务器返回404 Not found 时,它并不表示服务失败或错误,而是根本找不到该资源。如果在您的情况下,404 表示发生了错误并且必须使用 resilient approach 重试请求,则您必须抛出该异常以通知 Resilience4J 某事出错了。

    虽然我们正在努力改进我们的文档,但我建议您查看现有的 tutorial explaining resilience within the SAP Cloud SDK context。为了清楚起见,我们还在那里抛出ResilienceRuntimeException

    public List<BusinessPartner> execute() {
            return ResilienceDecorator.executeSupplier(this::run, myResilienceConfig, e -> {
                logger.warn("Fallback called because of exception.", e);
                return Collections.emptyList();
            });
        }
    
    private List<BusinessPartner> run() {
            try {
                return businessPartnerService
                        .getAllBusinessPartner()
                        .select(BusinessPartner.BUSINESS_PARTNER,
                                BusinessPartner.LAST_NAME,
                                BusinessPartner.FIRST_NAME,
                                BusinessPartner.IS_MALE,
                                BusinessPartner.IS_FEMALE,
                                BusinessPartner.CREATION_DATE,
                                BusinessPartner.TO_BUSINESS_PARTNER_ADDRESS
                                        .select(BusinessPartnerAddress.CITY_NAME,
                                                BusinessPartnerAddress.COUNTRY,
                                                BusinessPartnerAddress.TO_EMAIL_ADDRESS
                                                        .select(AddressEmailAddress.EMAIL_ADDRESS)
                                        )
                        )
                        .filter(BusinessPartner.BUSINESS_PARTNER_CATEGORY.eq(CATEGORY_PERSON))
                        .orderBy(BusinessPartner.LAST_NAME, Order.ASC)
                        .top(200)
                        .execute(destination);
            } catch (ODataException e) {
                throw new ResilienceRuntimeException(e);
            }
        }
    

    关于DestinationService 中的代码sn-p,我相信fetchDestinationsJson() 方法会引发一个隐式异常,从而让Resilience4J 知道某事出错了。而在您的情况下,HttpClient 在接收 404 时不会抛出任何东西,因为它是正确的响应代码。

    我也认为检查CircuitsBreakerexamples from Resilience4J library might be helpful

    希望对你有帮助:)

    【讨论】:

      【解决方案2】:

      不,您不必抛出ResilienceRuntimeException。事实上,SDK 只是使用它来将已检查和未检查的异常包装成一个未检查的异常,该异常包装了弹性调用中发生的各种故障。

      请用更多细节扩展您的问题,然后我将扩展此答案:

      • 您使用的是哪个版本的 SDK?
      • 您如何(以及多久)调用修饰的可调用对象?请展开代码块。
      • 请具体说明您观察到的行为。调用修饰的可调用对象时会引发什么异常?如果断路器打开,这应该是 CallNotPermittedException 包裹在 ResilienceRuntimeException
      • 减少可调用对象以简单地抛出异常以简化代码
      • 减少弹性配置以仅使用断路器(利用 ResilienceConfiguration.empty())。如果可行,请重新添加内容,直到无效为止。

      另请参阅documentation of resilience4j,SDK 在后台使用它来执行弹性操作。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2020-05-04
        • 2020-05-10
        • 2022-09-27
        • 1970-01-01
        • 1970-01-01
        • 2019-07-23
        • 1970-01-01
        相关资源
        最近更新 更多