如何基于SAP Cloud SDK全局实现死锁异常重试的Resilience机制
全局配置Resilience装饰器实现死锁自动重试
核心思路
无需逐个给SAP Cloud SDK调用添加装饰器,通过全局拦截或自定义客户端配置,将死锁重试逻辑注入所有OData请求,复用你已有的死锁判断规则。
具体实现方案
1. 定义通用死锁重试策略
基于你提供的死锁判断逻辑,创建可复用的Resilience4j重试配置:
import io.github.resilience4j.retry.Retry; import io.github.resilience4j.retry.RetryConfig; import com.sap.cloud.sdk.datamodel.odata.client.exception.ODataServiceErrorException; import java.time.Duration; public class DeadlockRetryConfig { public static Retry createDeadlockRetry() { RetryConfig config = RetryConfig.custom() .maxAttempts(3) // 可自定义重试次数 .waitDuration(Duration.ofSeconds(2)) // 重试间隔 .retryOnException(DeadlockRetryConfig::isDeadlockError) .build(); return Retry.of("deadlock-retry", config); } // 复用你的死锁判断逻辑 private static boolean isDeadlockError(Throwable throwable) { if (throwable instanceof ODataServiceErrorException serviceErrorException) { return serviceErrorException.getOdataError().getODataCode().equals("-2038"); } return false; } }
2. 全局包装OData客户端
通过自定义ODataClient,将重试逻辑注入所有SDK请求:
import com.sap.cloud.sdk.datamodel.odata.client.ODataClient; import com.sap.cloud.sdk.datamodel.odata.client.ODataClientBuilder; import com.sap.cloud.sdk.datamodel.odata.client.request.ODataRequest; import com.sap.cloud.sdk.datamodel.odata.client.response.ODataResponse; import io.github.resilience4j.retry.Retry; import java.util.function.Supplier; public class GlobalResilientODataClient { public static ODataClient getClient() { Retry deadlockRetry = DeadlockRetryConfig.createDeadlockRetry(); ODataClient baseClient = ODataClientBuilder.withCsrfTokenHandling().build(); // 包装客户端的请求执行逻辑,加入重试 return new ODataClient() { @Override public <T extends ODataResponse> T execute(ODataRequest request, Class<T> responseType) { Supplier<T> requestSupplier = () -> baseClient.execute(request, responseType); return Retry.decorateSupplier(deadlockRetry, requestSupplier).get(); } @Override public <T extends ODataResponse> T execute(ODataRequest request) { Supplier<T> requestSupplier = () -> (T) baseClient.execute(request); return Retry.decorateSupplier(deadlockRetry, requestSupplier).get(); } // 其余ODataClient接口方法直接委托给baseClient @Override public ODataRequestBuilder requestBuilder() { return baseClient.requestBuilder(); } // ... 其他方法同理实现委托 }; } }
3. 让生成的SDK代码使用全局客户端
生成的Business One服务类可通过构造方法指定自定义客户端:
// 示例:替换生成的服务类默认客户端 public class BusinessPartnerService extends DefaultBusinessPartnerService { public BusinessPartnerService() { super(GlobalResilientODataClient.getClient()); } }
如果是Spring环境,可通过依赖注入将自定义ODataClient设为全局默认,无需逐个修改服务类。
替代方案:Spring AOP全局拦截
若项目使用Spring,可通过切面自动拦截所有SDK请求并添加重试:
import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.springframework.stereotype.Component; import io.github.resilience4j.retry.Retry; import java.util.function.Supplier; @Aspect @Component public class SdkRequestRetryAspect { private final Retry deadlockRetry = DeadlockRetryConfig.createDeadlockRetry(); // 拦截所有生成的SDK服务类方法,替换为你的生成代码包路径 @Around("execution(* com.your.package.generated.*Service.*(..))") public Object retryOnDeadlock(ProceedingJoinPoint joinPoint) throws Throwable { Supplier<Object> requestSupplier = () -> { try { return joinPoint.proceed(); } catch (Throwable throwable) { throw new RuntimeException(throwable); } }; return Retry.decorateSupplier(deadlockRetry, requestSupplier).get(); } }
这种方式无需修改生成代码,更适合Spring生态项目。
内容的提问来源于stack exchange,提问作者Conner
相关产品推荐
相关产品推荐

