unb*_*chy 3 java error-handling compiler-errors http retry-logic
我正在尝试用纯 Java 创建一个实用程序类,其中包含指数退避算法实现所需的逻辑,并且具有完全抖动,因为将有多个客户端发送请求。我有另一个类,它的方法执行 GET 或 POST 请求并返回带有状态代码的响应。仅当状态代码位于 5xx 时,我才想重试(也称为使用指数退避策略)。当前代码未编译。
调用方法如下所示:
HttpResponse response = executeGetRequest( params );
int statusCode = response.getStatusCode();
//some status code validation
Run Code Online (Sandbox Code Playgroud)
我的 ExponentialBackoffStrategy 类是:
public class ExponentialBackoffStrategy {
private final long maxBackoff;
private long backoffValue;
private long attempts;
private static final long DEFAULT_MAX_RETRIES = 900_000;
private Random random = new Random();
public ExponentialBackoffStrategy( long maxBackoff ) {
this.maxBackoff = maxBackoff;
}
public long getWaitTimeExp() {
if( backoffValue >= maxBackoff ) {
return maxBackoff;
}
double pow = Math.pow( 2, attempts++ );
int rand = random.nextInt( 1000 );
backoffValue = ( long ) Math.min( pow + rand, maxBackoff );
return backoffValue;
}
public static ExponentialBackoffStrategy getDefault() {
return new ExponentialBackoffStrategy( DEFAULT_MAX_RETRIES );
}
}
Run Code Online (Sandbox Code Playgroud)
我想获得有关已实现类的一些反馈,了解我是否可以做得更好以及如何将其与调用者方法集成。我现在的想法是:
ExponentialBackoffStrategy backoff = ExponentialBackoffStrategy.getDefault();
boolean retry = false;
HttpResponse response = null;
int statusCode = 0;
do {
response = executeGetRequest( params );
statusCode = response.getStatusLine().getStatusCode();
if( statusCode >= 500 && statusCode < 600 ) {
retry = true;
try {
Thread.sleep( backoff.getWaitTimeExp() );
} catch ( InterruptedException e ) {
//handle exception
}
}
} while ( retry );
Run Code Online (Sandbox Code Playgroud)
任何帮助将不胜感激!
编辑: 响应实际上位于尝试资源中。
try ( HttpResponse response = backoff.attempt(
() -> executeGetRequest( params ),
r -> {
final int statusCode = response.getStatusLine().getStatusCode();
return statusCode < 500 || statusCode >= 600;
}
);)
Run Code Online (Sandbox Code Playgroud)
我遇到两个问题:
final int statusCode = response.getStatusLine().getStatusCode();
用红色下划线表示“变量“响应”可能尚未初始化”。试图将其放在 try 块之外并尝试使用资源不喜欢它。try ( HttpResponse response = executePostRequest( params ) ) {
您可以在课堂上引入更多样板,例如:
public class ExponentialBackoffStrategy {
...
@Nullable
public <T> T attempt(Supplier<T> action, Predicate<T> success) {
int attempts = 0;
T result = action.get();
while (!success.test(result)) {
try {
Thread.sleep(getWaitTimeExp(attempts++));
} catch ( InterruptedException e ) {
//handle exception
}
result = action.get();
}
return result;
}
}
Run Code Online (Sandbox Code Playgroud)
然后你可以这样使用:
ExponentialBackoffStrategy backoff = ExponentialBackoffStrategy.getDefault();
final HttpResponse response = backoff.attempt(
() -> executeGetRequest( params ),
r -> {
final int statusCode = r.getStatusLine().getStatusCode();
return statusCode < 500 || statusCode >= 600;
}
);
Run Code Online (Sandbox Code Playgroud)
这减少了程序中重复代码的数量,并且重试逻辑可以测试一次。
我已将可变状态(attempts
,并且backoffValue
可以删除)移出类并移至attempt()
函数中的局部变量中。这意味着单个ExponentialBackoffStrategy
实例可以安全地重用,也可以被多个线程使用。因此getWaitTimeExp
成为一个没有副作用的函数:
private long getWaitTimeExp(int attempts) {
final double pow = Math.pow( 2, attempts);
final int rand = random.nextInt( 1000 );
return ( long ) Math.min( pow + rand, maxBackoff );
}
Run Code Online (Sandbox Code Playgroud)
这是未经测试的代码!
您可能也应该在重试几次后停止重试。
为了测试这个你。希望将睡眠和随机数生成放入单独的组件中,然后注入到ExponentialBackoffStrategy
. 您的静态工厂方法可以注入生产实现,并且您的测试将使用ExponentialBackoffStrategy
构造函数并传递模拟。
所以你会有接口:
interface RandomNumber {
int next();
}
interface Sleeper {
void sleep(long milliseconds);
}
Run Code Online (Sandbox Code Playgroud)
和一个构造函数:
protected ExponentialBackoffStrategy(long maxBackoff, RandomNumber randomNumber, Sleeper sleeper) {
...
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
11633 次 |
最近记录: |