首页 > 解决方案 > 调用函数直到发生异常的 Guava 重试器

问题描述

假设我有一些这样的代码:

public void deleteResource(UUID resourceId) {
    deleteFromDb();
    deleteFromALotOfOtherPlaces();    // Takes a long time!
}

public DescribeResourceResult describeResource(UUID resourceId) throws ResourceNotFoundException {
    return getResourceDescription(resourceId);
}

不幸的是,删除并不表示它已完成。验证删除是否完成的唯一方法是调用describeResourcewhich 将在资源已被删除时抛出异常。

我想写一个重试器,它会反复调用describeResrouce直到 aResourceNotFoundException发生。我怎样才能做到这一点?

这是我到目前为止所拥有的:

final Retryer<ResourceNotFoundException> deleteResourceRetryer = RetryerBuilder.<ResourceNotFoundException>newBuilder()
                .withWaitStrategy(WaitStrategies.fixedWait(500, TimeUnit.MILLISECONDS))
                .withStopStrategy(StopStrategies.stopAfterDelay(10, TimeUnit.SECONDS))
                .build();

// Error: Bad return type in lambda expression: DescribeResourceResult cannot be converted to ResourceNotFoundException
deleteResourceRetryer.call(() -> describeResource(resourceId));

谢谢!

标签: javaguava

解决方案


我对 Guava 不太熟悉Retryer,因此经过短暂调查后,我找不到现成的StopStrategy,所以我的建议是自己实施

static class OnResourceNotFoundExceptionStopStrategy implements StopStrategy {

    @Override
    public boolean shouldStop(Attempt attempt) {
        if (attempt.hasException() 
                     && attempt.getExceptionCause() instanceof ResourceNotFoundException) {
            return true;
        }
        return false;
    }

}

使用该策略重试将在您捕获时停止ResourceNotFoundException。之后修复类型并正确定义Retryer

final Retryer<DescribeResourceResult> deleteResourceRetryer = RetryerBuilder
            .<DescribeResourceResult>newBuilder()
            .retryIfResult(Predicates.notNull())
            .withWaitStrategy(WaitStrategies.fixedWait(500, TimeUnit.MILLISECONDS))
            .withStopStrategy(new OnResourceNotFoundExceptionStopStrategy())
            .build();

最后,开始重试

try {
    deleteResourceRetryer.call(() -> describeResource(resourceId));
} catch (ExecutionException e) {
    // should not happens, because you will retry if any exception rather
    // than ResourceNotFoundException raised in your describeResource method
} catch (RetryException e) {
    // should not happens, because my implementation of StopStrategy
    // (as it looks in this example) is effectively infinite, until target exception.
    // For sure you're free to override it to anything you want
}

希望能帮助到你!


推荐阅读